From b4efd15253cee18496388d63d0560ab9fee916d6 Mon Sep 17 00:00:00 2001 From: "junsung.yoon" Date: Fri, 21 Aug 2020 15:20:52 +0900 Subject: [PATCH 01/26] =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20=EB=94=94=EB=A0=89?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20archive=20+=20=EC=83=88=EB=A1=9C=EC=9A=B4?= =?UTF-8?q?=20auth=20=EB=94=94=EB=A0=89=ED=86=A0=EB=A6=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/archive/auth.ctrl.js | 7 +++++++ src/routes/archive/index.js | 7 +++++++ src/routes/{auth => auth_archive}/auth.ctrl.js | 0 src/routes/{auth => auth_archive}/index.js | 0 src/routes/index.js | 2 +- 5 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/routes/archive/auth.ctrl.js create mode 100644 src/routes/archive/index.js rename src/routes/{auth => auth_archive}/auth.ctrl.js (100%) rename src/routes/{auth => auth_archive}/index.js (100%) diff --git a/src/routes/archive/auth.ctrl.js b/src/routes/archive/auth.ctrl.js new file mode 100644 index 0000000..854cf2e --- /dev/null +++ b/src/routes/archive/auth.ctrl.js @@ -0,0 +1,7 @@ +const models = require('../../database/models'); +const SSOClient = require('../../utils/sso'); +const { parseJSON } = require('../../utils'); + +exports.login = async (ctx) => { + +}; diff --git a/src/routes/archive/index.js b/src/routes/archive/index.js new file mode 100644 index 0000000..ce5cd23 --- /dev/null +++ b/src/routes/archive/index.js @@ -0,0 +1,7 @@ +const Router = require('koa-router'); +const auth = new Router(); +const authCtrl = require('./auth.ctrl'); + +auth.post('/login', authCtrl.login); + +module.exports = auth; \ No newline at end of file diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth_archive/auth.ctrl.js similarity index 100% rename from src/routes/auth/auth.ctrl.js rename to src/routes/auth_archive/auth.ctrl.js diff --git a/src/routes/auth/index.js b/src/routes/auth_archive/index.js similarity index 100% rename from src/routes/auth/index.js rename to src/routes/auth_archive/index.js diff --git a/src/routes/index.js b/src/routes/index.js index 4c15329..074ecdd 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,7 +4,7 @@ const posts = require('./posts'); const banners = require('./banners'); const bulletins = require('./bulletins'); const admins = require('./admins'); -const auth = require('./auth'); +const auth = require('./auth_archive'); const router = new Router(); From ff2c320219b2f51d0ec4c6af2a9008d647bec856 Mon Sep 17 00:00:00 2001 From: "junsung.yoon" Date: Fri, 21 Aug 2020 17:14:42 +0900 Subject: [PATCH 02/26] POST /login --- package.json | 3 +- src/database/models/user.js | 5 +- src/routes/archive/auth.ctrl.js | 7 --- src/routes/auth/auth.ctrl.js | 32 ++++++++++ src/routes/auth/generateToken.js | 21 +++++++ src/routes/{archive => auth}/index.js | 2 +- src/routes/index.js | 2 +- yarn.lock | 87 ++++++++++++++++++++++++++- 8 files changed, 144 insertions(+), 15 deletions(-) delete mode 100644 src/routes/archive/auth.ctrl.js create mode 100644 src/routes/auth/auth.ctrl.js create mode 100644 src/routes/auth/generateToken.js rename src/routes/{archive => auth}/index.js (86%) diff --git a/package.json b/package.json index 9c89bb9..3693ba5 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "cors": "^2.8.5", "crypto": "^1.0.1", "dotenv": "^8.2.0", + "jsonwebtoken": "^8.5.1", "koa": "^2.11.0", "koa-body": "^4.1.1", "koa-helmet": "^5.2.0", @@ -43,4 +44,4 @@ "devDependencies": { "eslint": "^7.7.0" } -} \ No newline at end of file +} diff --git a/src/database/models/user.js b/src/database/models/user.js index 758659c..2d51990 100644 --- a/src/database/models/user.js +++ b/src/database/models/user.js @@ -9,10 +9,7 @@ module.exports = (sequelize, DataTypes) => { primaryKey: true, }, ku_std_no: DataTypes.STRING, - kaist_uid: { - type: DataTypes.STRING, - primaryKey: true, - }, + kaist_uid: DataTypes.STRING, ku_employee_number: DataTypes.STRING, displayname: DataTypes.STRING, ku_acad_name: DataTypes.STRING, diff --git a/src/routes/archive/auth.ctrl.js b/src/routes/archive/auth.ctrl.js deleted file mode 100644 index 854cf2e..0000000 --- a/src/routes/archive/auth.ctrl.js +++ /dev/null @@ -1,7 +0,0 @@ -const models = require('../../database/models'); -const SSOClient = require('../../utils/sso'); -const { parseJSON } = require('../../utils'); - -exports.login = async (ctx) => { - -}; diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js new file mode 100644 index 0000000..21eaa7e --- /dev/null +++ b/src/routes/auth/auth.ctrl.js @@ -0,0 +1,32 @@ +const models = require('../../database/models'); +const { generateToken } = require('./generateToken'); + +exports.login = async (ctx) => { + const { k_uid, user_info } = ctx.request.body; + const account = await models.user.findOne({ where: { kaist_uid: k_uid } }); + + const updatedAccount = { + ku_std_no: user_info.ku_std_n || null, + ku_employee_number: user_info.ku_employee_number || null, + displayname: user_info.displayname || null, + ku_acad_name: user_info.ku_acad_name || null, + ku_kname: user_info.ku_kname || null, + } + if (account) { + await models.user.update(updatedAccount, { where: { id: account.id } }) + + let token = null; + try { + token = await generateToken({ id: account.id }); + } catch (e) { + ctx.throw(500, e); + } + console.log(token); + + ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 }); + ctx.body = account; + } else { + ctx.status = 403; + return; + } +}; diff --git a/src/routes/auth/generateToken.js b/src/routes/auth/generateToken.js new file mode 100644 index 0000000..ace62ab --- /dev/null +++ b/src/routes/auth/generateToken.js @@ -0,0 +1,21 @@ +const jwtSecret = process.env.JWT_SECRET; +const jwt = require('jsonwebtoken'); + +function generateToken(payload) { + return new Promise( + (resolve, reject) => { + jwt.sign( + payload, + jwtSecret, + { + expiresIn: '7d', + }, (error, token) => { + if (error) reject(error); + resolve(token); + }, + ); + }, + ); +}; +exports.generateToken = generateToken; + diff --git a/src/routes/archive/index.js b/src/routes/auth/index.js similarity index 86% rename from src/routes/archive/index.js rename to src/routes/auth/index.js index ce5cd23..0749991 100644 --- a/src/routes/archive/index.js +++ b/src/routes/auth/index.js @@ -4,4 +4,4 @@ const authCtrl = require('./auth.ctrl'); auth.post('/login', authCtrl.login); -module.exports = auth; \ No newline at end of file +module.exports = auth; diff --git a/src/routes/index.js b/src/routes/index.js index 074ecdd..4c15329 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,7 +4,7 @@ const posts = require('./posts'); const banners = require('./banners'); const bulletins = require('./bulletins'); const admins = require('./admins'); -const auth = require('./auth_archive'); +const auth = require('./auth'); const router = new Router(); diff --git a/yarn.lock b/yarn.lock index bbd65d8..87fd0e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -380,6 +380,11 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + bytes@3.1.0, bytes@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -736,6 +741,13 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1396,6 +1408,39 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + keygrip@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" @@ -1547,11 +1592,46 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + lodash@^4.17.1: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" @@ -2138,6 +2218,11 @@ safe-buffer@5.1.2: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -2150,7 +2235,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== From bc4e54157a8cb79a0e6c98c065dddbcbc3145d3a Mon Sep 17 00:00:00 2001 From: "junsung.yoon" Date: Fri, 21 Aug 2020 17:18:17 +0900 Subject: [PATCH 03/26] delete useless column --- src/database/models/user.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/database/models/user.js b/src/database/models/user.js index 2d51990..d010326 100644 --- a/src/database/models/user.js +++ b/src/database/models/user.js @@ -14,11 +14,6 @@ module.exports = (sequelize, DataTypes) => { displayname: DataTypes.STRING, ku_acad_name: DataTypes.STRING, ku_kname: DataTypes.STRING, - user_id: DataTypes.STRING, - access_token: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - }, }, { underscored: true, From a8275059d901eed5a41f029e81169a6127a87cc2 Mon Sep 17 00:00:00 2001 From: "junsung.yoon" Date: Fri, 21 Aug 2020 17:24:17 +0900 Subject: [PATCH 04/26] POST /register --- src/routes/auth/auth.ctrl.js | 25 ++++++++++++++++++------- src/routes/auth/generateToken.js | 11 ++++++++++- src/routes/auth/index.js | 1 + 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index 21eaa7e..e7fb381 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -15,13 +15,7 @@ exports.login = async (ctx) => { if (account) { await models.user.update(updatedAccount, { where: { id: account.id } }) - let token = null; - try { - token = await generateToken({ id: account.id }); - } catch (e) { - ctx.throw(500, e); - } - console.log(token); + const token = await generateToken({ id: account.id }); ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 }); ctx.body = account; @@ -30,3 +24,20 @@ exports.login = async (ctx) => { return; } }; + +exports.register = async (ctx) => { + const { k_uid, user_info } = ctx.request.body; + const userData = { + kaist_uid: k_uid, + ku_std_no: user_info.ku_std_n || null, + ku_employee_number: user_info.ku_employee_number || null, + displayname: user_info.displayname || null, + ku_acad_name: user_info.ku_acad_name || null, + ku_kname: user_info.ku_kname || null, + }; + const user = await models.user.create(userData); + const token = await generateToken({ id: user.id }); + + ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 }); + ctx.body = user; +} diff --git a/src/routes/auth/generateToken.js b/src/routes/auth/generateToken.js index ace62ab..1bfdf89 100644 --- a/src/routes/auth/generateToken.js +++ b/src/routes/auth/generateToken.js @@ -17,5 +17,14 @@ function generateToken(payload) { }, ); }; -exports.generateToken = generateToken; +exports.generateToken = async (payload) => { + let token = null; + try { + token = await generateToken(payload); + } catch (e) { + ctx.throw(500, e); + } + console.log(token); + return token; +}; diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index 0749991..8d8ca4d 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -3,5 +3,6 @@ const auth = new Router(); const authCtrl = require('./auth.ctrl'); auth.post('/login', authCtrl.login); +auth.post('/register', authCtrl.register); module.exports = auth; From 2d8992e5f5eef726616e31c57547e0151be9edd5 Mon Sep 17 00:00:00 2001 From: "junsung.yoon" Date: Fri, 21 Aug 2020 17:43:49 +0900 Subject: [PATCH 05/26] validate token --- index.js | 2 ++ src/routes/auth/generateToken.js | 1 - src/utils/index.js | 44 +++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index ab280f3..3969123 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ const helmet = require('koa-helmet'); const passport = require('koa-passport'); const swagger = require('koa2-swagger-ui'); const swaggerDoc = require('./src/utils/swaggerDef.js'); +const { jwtMiddleware } = require('./src/utils'); const run = async () => { const app = new Koa(); @@ -29,6 +30,7 @@ const run = async () => { require('./src/config/accesstoken-strategy.js'); app.use(logger()); app.use(bodyParser()); + app.use(jwtMiddleware); app.use(router.routes()).use(router.allowedMethods()); app.use( swagger({ diff --git a/src/routes/auth/generateToken.js b/src/routes/auth/generateToken.js index 1bfdf89..b5d1817 100644 --- a/src/routes/auth/generateToken.js +++ b/src/routes/auth/generateToken.js @@ -24,7 +24,6 @@ exports.generateToken = async (payload) => { } catch (e) { ctx.throw(500, e); } - console.log(token); return token; }; diff --git a/src/utils/index.js b/src/utils/index.js index 20d0511..41ad5ef 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -12,4 +12,46 @@ const parseJSON = (jsonString, fallback = {}) => { } }; -module.exports = { parseJSON }; +const jwtSecret = process.env.JWT_SECRET; +const jwt = require('jsonwebtoken'); + +function decodeToken(token) { + return new Promise( + (resolve, reject) => { + jwt.verify(token, jwtSecret, (error, decoded) => { + if (error) reject(error); + resolve(decoded); + }) + }, + ) +} + +async function jwtMiddleware(ctx, next) { + const token = ctx.cookies.get('access_token'); // ctx 에서 access_token 을 읽어옵니다 + if (!token) return next(); // 토큰이 없으면 바로 다음 작업을 진행합니다. + + try { + const decoded = await decodeToken(token); // 토큰을 디코딩 합니다 + // 토큰 만료일이 하루밖에 안남으면 토큰을 재발급합니다 + if (Date.now() / 1000 - decoded.iat > 60 * 60 * 24) { + // 하루가 지나면 갱신해준다. + const { id } = decoded; + const { generateToken } = require('../routes/auth/generateToken'); + const freshToken = await generateToken({ id }); + ctx.cookies.set('access_token', freshToken, { + maxAge: 1000 * 60 * 60 * 24 * 7, // 7days + httpOnly: true, + }); + } + + // ctx.request.user 에 디코딩된 값을 넣어줍니다 + ctx.request.user = decoded; + } catch (e) { + // token validate 실패 + ctx.request.user = null; + } + + return next(); +} + +module.exports = { parseJSON, jwtMiddleware }; From d48f1f68f8b46a74f00a376e5b4929dddb3b0173 Mon Sep 17 00:00:00 2001 From: "junsung.yoon" Date: Fri, 21 Aug 2020 17:46:19 +0900 Subject: [PATCH 06/26] remove useless modules --- src/routes/auth_archive/auth.ctrl.js | 110 --------------------------- src/routes/auth_archive/index.js | 9 --- src/utils/sso.js | 21 ----- 3 files changed, 140 deletions(-) delete mode 100644 src/routes/auth_archive/auth.ctrl.js delete mode 100644 src/routes/auth_archive/index.js delete mode 100644 src/utils/sso.js diff --git a/src/routes/auth_archive/auth.ctrl.js b/src/routes/auth_archive/auth.ctrl.js deleted file mode 100644 index 0043028..0000000 --- a/src/routes/auth_archive/auth.ctrl.js +++ /dev/null @@ -1,110 +0,0 @@ -const models = require('../../database/models'); -const SSOClient = require('../../utils/sso'); -const { parseJSON } = require('../../utils'); - -exports.login = async (ctx) => { - const { url, state } = SSOClient.getLoginParams('login'); - //ctx.request.state = ctx.request.header.referrer; //요청을 보낸곳의 url - //ctx.response.session.state = state; - ctx.redirect(url); -}; - -exports.register = async (ctx) => { - const { url, state } = SSOClient.getLoginParams('register'); - //ctx.request.session.state = state; - ctx.redirect(url); -}; - -exports.signUp = async (ctx) => { - //const stateBefore = ctx.request.session.state; - - console.log(ctx); - const { result, success, user_id, k_uid, state } = ctx.request.body; - - // if (stateBefore !== state) { - // ctx.status = 401; - // ctx.body = { - // error: "TOKEN MISMATCH", - // }; - // } - - const userData = getUserData(result); - - const user = await models.user.findOne({ - where: { kaist_uid: userData.kaist_uid }, - }); - - const path = state.split(',')[0]; - - if (path == 'login') { - if (!user) { - //login 시도 + DB에 저장된 정보 없을시 -> 개인정보 처리 동의 화면으로 Redirect - ctx.redirect('https://student.kaist.ac.kr/web/auth/agreement'); - } else { - //login 시도 + DB에 저장된 정보 있을시 -> 유저 정보 업데이트 후, 로그인 성공 - //메인 화면으로 redirect - //todo : 원래 로그인 전에 유저가 있던 페이지로 redirect - await models.user.update(userData, { - where: { - kaist_uid: userData.kaist_uid, - }, - }); - ctx.body = { - user: userData, - access_token: user.access_token, - }; - - ctx.redirect('https://student.kaist.ac.kr/web/main'); - } - } else if (path == 'register') { - //register 시도 + DB에 저장된 정보 없을시 - //user DB에 저장하고 메인 화면으로 redirect! 로그인 성공! - if (!user) { - const registeredUser = await models.user.create(userData); - console.log(models.user.create(userData)); - - ctx.body = { - user: userData, - access_token: registeredUser.access_token, - }; - - ctx.redirect('https://student.kaist.ac.kr/web/main'); - } else { - console.log(user); - ctx.body = { - user: userData, - access_token: user.access_token, - message: '이미 가입한 적 있는 회원입니다!', - }; - - ctx.redirect('https://student.kaist.ac.kr/web/main'); - } - } else { - console.error('WRONG STATE!'); - } -}; - -const getUserData = (userData) => { - const json = parseJSON(userData); - - const info = json.dataMap.USER_INFO; - - return { - ku_std_no: info.ku_std_no, - kaist_uid: info.kaist_uid, - ku_employee_number: info.ku_employee_number, - displayname: info.displayname, - ku_acad_name: info.ku_acad_name, - ku_kname: info.ku_kname, - }; -}; -/** - * ctx.body - * { - result: '{"dataMap":{"USER_INFO":{"ku_std_no":"20180419","kaist_uid":"00094223","ku_employee_number":null,"displayname":"YOON, JUNSUNG","ku_acad_name":"School of Computing","ku_kname":"윤준성"},"state":"1959a19786cb1e96b326","REDIRECT_URL":"https://student.kaist.ac.kr/web/api/auth/signup"},"error":false,"errorCode":null,"errorMessage":null}', - success: 'true', - user_id: 'yoonjs0510', - k_uid: '00094223', - state: '1959a19786cb1e96b326' -} - */ diff --git a/src/routes/auth_archive/index.js b/src/routes/auth_archive/index.js deleted file mode 100644 index 6fa5613..0000000 --- a/src/routes/auth_archive/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const Router = require('koa-router'); -const auth = new Router(); -const authCtrl = require('./auth.ctrl'); - -auth.get('/login', authCtrl.login); -auth.get('/register', authCtrl.register); -auth.post('/signup', authCtrl.signUp); - -module.exports = auth; diff --git a/src/utils/sso.js b/src/utils/sso.js deleted file mode 100644 index c3680fa..0000000 --- a/src/utils/sso.js +++ /dev/null @@ -1,21 +0,0 @@ -const crypto = require('crypto'); - -class Client { - getLoginParams(str) { - const state = str.concat(',', crypto.randomBytes(10).toString('hex')); - const params = { - client_id: 'KAIPEDIA', - redirect_url: 'https://student.kaist.ac.kr/web/main', - state, - }; - const url = [ - 'https://iam2.kaist.ac.kr/api/sso/commonLogin', - Object.entries(params) - .map((e) => e.join('=')) - .join('&'), - ].join('?'); - return { url, state }; - } -} - -module.exports = new Client(); From a0f29cef7a482f4e1703bb0ca127e65e5022bb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EB=8B=A4=EC=9D=80?= Date: Sat, 22 Aug 2020 23:29:37 +0900 Subject: [PATCH 07/26] Add cancelRequest api --- src/database/models/cancel_request.js | 29 ++++++ src/database/models/user.js | 5 +- src/routes/auth/auth.ctrl.js | 5 +- src/routes/auth/index.js | 2 +- .../cancelRequest/cancelRequest.ctrl.js | 91 +++++++++++++++++++ src/routes/cancelRequest/index.js | 10 ++ src/routes/index.js | 2 + 7 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 src/database/models/cancel_request.js create mode 100644 src/routes/cancelRequest/cancelRequest.ctrl.js create mode 100644 src/routes/cancelRequest/index.js diff --git a/src/database/models/cancel_request.js b/src/database/models/cancel_request.js new file mode 100644 index 0000000..f20ff97 --- /dev/null +++ b/src/database/models/cancel_request.js @@ -0,0 +1,29 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + const cancel_request = sequelize.define( + "cancel_request", + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + ku_std_no: DataTypes.STRING, + displayname: DataTypes.STRING, + ku_kname: DataTypes.STRING, + }, + { + underscored: true, + freezeTableName: true, + charset: "utf8", + collate: "utf8_general_ci", + } + ); + cancel_request.associate = function (models) { + // associations can be defined here + models.cancel_request.belongsTo(models.user, { + foreignKey: "id" + }) + }; + return cancel_request; +}; diff --git a/src/database/models/user.js b/src/database/models/user.js index 997673e..0e323c8 100644 --- a/src/database/models/user.js +++ b/src/database/models/user.js @@ -9,10 +9,7 @@ module.exports = (sequelize, DataTypes) => { primaryKey: true, }, ku_std_no: DataTypes.STRING, - kaist_uid: { - type: DataTypes.STRING, - primaryKey: true, - }, + kaist_uid: DataTypes.STRING, ku_employee_number: DataTypes.STRING, displayname: DataTypes.STRING, ku_acad_name: DataTypes.STRING, diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index 70a9b07..0cee061 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -10,9 +10,8 @@ exports.login = async (ctx) => { }; exports.register = async (ctx) => { - const { url, state } = SSOClient.getLoginParams("register"); - //ctx.request.session.state = state; - ctx.redirect(url); + const body = ctx.request.body; + await models.user.create(body); }; exports.signUp = async (ctx) => { diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index f8b4bad..549dba0 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -3,7 +3,7 @@ const auth = new Router(); const authCtrl = require("./auth.ctrl"); auth.get("/login", authCtrl.login); -auth.get("/register", authCtrl.register); +auth.post("/register", authCtrl.register); auth.post("/signup", authCtrl.signUp); module.exports = auth; diff --git a/src/routes/cancelRequest/cancelRequest.ctrl.js b/src/routes/cancelRequest/cancelRequest.ctrl.js new file mode 100644 index 0000000..c5b1db2 --- /dev/null +++ b/src/routes/cancelRequest/cancelRequest.ctrl.js @@ -0,0 +1,91 @@ +const models = require("../../database/models"); +const Op = require("sequelize").Op; + +/** + * POST /cancelRequest + * {id} + */ +exports.write = async (ctx) => { + const { id } = ctx.request.body; + const res = await models.user.findOne({ + where: { id }, + }) + if (!res) ctx.body = "No user found"; + console.log(res.ku_std_no) + const { ku_std_no, displayname, ku_kname } = res; + await models.cancel_request + .create({ id, ku_std_no, displayname, ku_kname }) + .then((res) => { + ctx.body = res; + }) + .catch((err) => { + console.log(err); + }); +}; + +/** + * GET /cancelRequest + */ + +exports.list = async (ctx) => { + await models.cancel_request + .findAll({ + order: [["ku_std_no", "ASC"]], + }) + .then((res) => { + ctx.body = res; + }) + .catch((err) => { + console.log(err); + }); +}; + +/** + * GET /cancelRequest/:id + */ + +exports.read = async (ctx) => { + const { id } = ctx.params; + + await models.cancel_request + .findOne({ + where: { id }, + }) + .then((res) => { + if (!res) + ctx.body = { exists: false }; + else + ctx.body = { exists: true }; + }) + .catch((err) => { + console.log(err) + ctx.body = { exists: false }; + }); +}; + +/** + * DELETE /cancelRequest/:id + */ + +exports.remove = async (ctx) => { + const { id } = ctx.params; + + await models.cancel_request + .destroy({ + where: { id: id }, + }) + .then((res) => { + if (!res) { + ctx.status = 404; + ctx.body = { + message: "id가 존재하지 않습니다.", + }; + } else { + console.log("cancel request 삭제 성공!"); + ctx.status = 204; + } + }) + .catch((err) => { + console.log(err); + }); +}; \ No newline at end of file diff --git a/src/routes/cancelRequest/index.js b/src/routes/cancelRequest/index.js new file mode 100644 index 0000000..62aa5d1 --- /dev/null +++ b/src/routes/cancelRequest/index.js @@ -0,0 +1,10 @@ +const Router = require("koa-router"); +const cancelRequest = new Router(); +const cancelRequestCtrl = require("./cancelRequest.ctrl"); + +cancelRequest.post("/", cancelRequestCtrl.write); +cancelRequest.get("/", cancelRequestCtrl.list); +cancelRequest.get("/:id", cancelRequestCtrl.read); +cancelRequest.delete("/:id", cancelRequestCtrl.remove); + +module.exports = cancelRequest; diff --git a/src/routes/index.js b/src/routes/index.js index 9121077..c9aefd5 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -5,6 +5,7 @@ const banners = require("./banners"); const bulletins = require("./bulletins"); const admins = require("./admins"); const auth = require("./auth"); +const cancelRequest = require("./cancelRequest"); const router = new Router(); @@ -17,5 +18,6 @@ router.use("/posts", posts.routes()); router.use("/admins", admins.routes()); router.use("/banners", banners.routes()); router.use("/bulletins", bulletins.routes()); +router.use("/cancelRequest", cancelRequest.routes()); module.exports = router; From dfde57bf09ac3bc3345c8728b9fc5caba4f96952 Mon Sep 17 00:00:00 2001 From: winningarc Date: Mon, 24 Aug 2020 05:30:20 +0900 Subject: [PATCH 08/26] feat(login): finish login implementation with cookies --- index.js | 38 +++++++++--------- src/database/models/user.js | 10 ++--- src/routes/admins/admins.ctrl.js | 22 +++++------ src/routes/auth/auth.ctrl.js | 67 ++++++++++++++------------------ src/routes/auth/generateToken.js | 38 ++++++++---------- src/routes/auth/index.js | 9 +++-- src/routes/posts/index.js | 22 ++++------- src/utils/index.js | 33 ++++++++-------- 8 files changed, 110 insertions(+), 129 deletions(-) diff --git a/index.js b/index.js index 3969123..da42df8 100644 --- a/index.js +++ b/index.js @@ -1,15 +1,15 @@ -require('dotenv').config(); -const Koa = require('koa'); -const bodyParser = require('koa-body'); -const cors = require('@koa/cors'); -const logger = require('koa-logger'); -const router = require('./src/routes'); -const models = require('./src/database/models/index.js'); -const helmet = require('koa-helmet'); -const passport = require('koa-passport'); -const swagger = require('koa2-swagger-ui'); -const swaggerDoc = require('./src/utils/swaggerDef.js'); -const { jwtMiddleware } = require('./src/utils'); +require("dotenv").config(); +const Koa = require("koa"); +const bodyParser = require("koa-body"); +const cors = require("@koa/cors"); +const logger = require("koa-logger"); +const router = require("./src/routes"); +const models = require("./src/database/models/index.js"); +const helmet = require("koa-helmet"); +const passport = require("koa-passport"); +const swagger = require("koa2-swagger-ui"); +const swaggerDoc = require("./src/utils/swaggerDef.js"); +const { jwtMiddleware } = require("./src/utils"); const run = async () => { const app = new Koa(); @@ -17,28 +17,28 @@ const run = async () => { models.sequelize .sync() .then(() => { - console.log(' DB 연결 성공'); + console.log(" DB 연결 성공"); }) .catch((err) => { - console.log('연결 실패'); + console.log("연결 실패"); console.log(err); }); - app.use(cors()); + app.use(cors({ credentials: true })); app.use(helmet()); app.use(passport.initialize()); - require('./src/config/accesstoken-strategy.js'); + require("./src/config/accesstoken-strategy.js"); app.use(logger()); app.use(bodyParser()); app.use(jwtMiddleware); app.use(router.routes()).use(router.allowedMethods()); app.use( swagger({ - routePrefix: '/swagger', + routePrefix: "/swagger", swaggerOptions: { - url: '/swagger.json', + url: "/swagger.json", }, - }), + }) ); app.use(swaggerDoc.routes()); diff --git a/src/database/models/user.js b/src/database/models/user.js index d010326..cbf8c85 100644 --- a/src/database/models/user.js +++ b/src/database/models/user.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; module.exports = (sequelize, DataTypes) => { const user = sequelize.define( - 'user', + "user", { id: { type: DataTypes.UUID, @@ -19,9 +19,9 @@ module.exports = (sequelize, DataTypes) => { underscored: true, freezeTableName: true, paranoid: true, - charset: 'utf8', - collate: 'utf8_general_ci', - }, + charset: "utf8", + collate: "utf8_general_ci", + } ); user.associate = function (models) { // associations can be defined here diff --git a/src/routes/admins/admins.ctrl.js b/src/routes/admins/admins.ctrl.js index 60bc896..79fccc0 100644 --- a/src/routes/admins/admins.ctrl.js +++ b/src/routes/admins/admins.ctrl.js @@ -1,11 +1,11 @@ -const models = require('../../database/models'); -const crypto = require('crypto'); -const { access } = require('fs'); +const models = require("../../database/models"); +const crypto = require("crypto"); +const { access } = require("fs"); var genRandomString = function (length) { return crypto .randomBytes(Math.ceil(length / 2)) - .toString('hex') /** convert to hexadecimal format */ + .toString("hex") /** convert to hexadecimal format */ .slice(0, length); /** return required number of characters */ }; @@ -57,12 +57,12 @@ exports.login = async (ctx) => { if (!res) { ctx.status = 404; ctx.body = { - message: '로그인 실패!', + message: "로그인 실패!", }; } else { - const hash = crypto.createHmac('sha512', res.salt); + const hash = crypto.createHmac("sha512", res.salt); hash.update(password); - const value = hash.digest('hex'); + const value = hash.digest("hex"); if (value === res.password) { ctx.body = { email: res.email, @@ -76,9 +76,9 @@ exports.login = async (ctx) => { * GET /admins/check?access_token */ exports.check = async (ctx) => { - const url = new URLSearchParams(ctx.url.split('?')[1]); + const url = new URLSearchParams(ctx.url.split("?")[1]); const res = await models.admin.findOne({ - where: { access_token: url.get('access_token') }, + where: { access_token: url.get("access_token") }, }); if (!res) { ctx.body = { @@ -100,8 +100,8 @@ exports.register = async (ctx) => { const res = await models.admin.findOne({ where: { email } }); if (res) return; var salt = genRandomString(16); - const hash = crypto.createHmac('sha512', salt); + const hash = crypto.createHmac("sha512", salt); hash.update(password); - const value = hash.digest('hex'); + const value = hash.digest("hex"); ctx.body = await models.admin.create({ email, salt, password: value }); }; diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index e7fb381..e942c4f 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -1,43 +1,36 @@ -const models = require('../../database/models'); -const { generateToken } = require('./generateToken'); +const models = require("../../database/models"); +const { generateToken } = require("./generateToken"); +const e = require("cors"); -exports.login = async (ctx) => { - const { k_uid, user_info } = ctx.request.body; - const account = await models.user.findOne({ where: { kaist_uid: k_uid } }); - - const updatedAccount = { - ku_std_no: user_info.ku_std_n || null, - ku_employee_number: user_info.ku_employee_number || null, - displayname: user_info.displayname || null, - ku_acad_name: user_info.ku_acad_name || null, - ku_kname: user_info.ku_kname || null, - } - if (account) { - await models.user.update(updatedAccount, { where: { id: account.id } }) - - const token = await generateToken({ id: account.id }); - - ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 }); - ctx.body = account; +exports.signup = async (ctx) => { + const { USER_INFO, state } = JSON.parse(ctx.request.body.result).dataMap; + var record = await models.user.findOne({ where: USER_INFO }); + if (record || state === process.env.REGISTER_KEY) { + if (!record) { + console.log("REGISTER"); + record = await models.user.create(USER_INFO); + } else { + console.log("LOGIN"); + } + const token = await generateToken({ id: record.id }); + ctx.cookies.set("access_token", token, { + maxAge: 1000 * 60 * 60 * 24 * 7, + overwrite: true, + }); + ctx.redirect(`${process.env.WEB_FRONTEND}/web/main`); } else { - ctx.status = 403; - return; + console.log("AGREEMENT"); + ctx.redirect(`${process.env.WEB_FRONTEND}/web/auth/agreement/login`); } }; -exports.register = async (ctx) => { - const { k_uid, user_info } = ctx.request.body; - const userData = { - kaist_uid: k_uid, - ku_std_no: user_info.ku_std_n || null, - ku_employee_number: user_info.ku_employee_number || null, - displayname: user_info.displayname || null, - ku_acad_name: user_info.ku_acad_name || null, - ku_kname: user_info.ku_kname || null, - }; - const user = await models.user.create(userData); - const token = await generateToken({ id: user.id }); +exports.logout = async (ctx) => { + ctx.cookies.set("access_token", "", { overwrite: true }); + ctx.response.status = 200; +}; - ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 }); - ctx.body = user; -} +exports.checkUser = async (ctx) => { + const { id } = ctx.request.user; + const user = await models.user.findOne({ where: { id } }); + ctx.response.body = { auth: user ? "user" : false }; +}; diff --git a/src/routes/auth/generateToken.js b/src/routes/auth/generateToken.js index b5d1817..0d10043 100644 --- a/src/routes/auth/generateToken.js +++ b/src/routes/auth/generateToken.js @@ -1,29 +1,23 @@ const jwtSecret = process.env.JWT_SECRET; -const jwt = require('jsonwebtoken'); +const jwt = require("jsonwebtoken"); function generateToken(payload) { - return new Promise( - (resolve, reject) => { - jwt.sign( - payload, - jwtSecret, - { - expiresIn: '7d', - }, (error, token) => { - if (error) reject(error); - resolve(token); - }, - ); - }, - ); -}; + return new Promise((resolve, reject) => { + jwt.sign( + payload, + jwtSecret, + { + expiresIn: "7d", + }, + (error, token) => { + if (error) reject(error); + resolve(token); + } + ); + }); +} exports.generateToken = async (payload) => { let token = null; - try { - token = await generateToken(payload); - } catch (e) { - ctx.throw(500, e); - } + token = await generateToken(payload); return token; }; - diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index 8d8ca4d..5680036 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -1,8 +1,9 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); const auth = new Router(); -const authCtrl = require('./auth.ctrl'); +const authCtrl = require("./auth.ctrl"); -auth.post('/login', authCtrl.login); -auth.post('/register', authCtrl.register); +auth.post("/signup", authCtrl.signup); +auth.get("/checkUser", authCtrl.checkUser); +auth.get("/logout", authCtrl.logout); module.exports = auth; diff --git a/src/routes/posts/index.js b/src/routes/posts/index.js index bc09576..23209c3 100644 --- a/src/routes/posts/index.js +++ b/src/routes/posts/index.js @@ -1,19 +1,11 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); const posts = new Router(); -const postsCtrl = require('./posts.ctrl'); +const postsCtrl = require("./posts.ctrl"); -const printInfo = (ctx) => { - ctx.body = { - method: ctx.method, - path: ctx.path, - params: ctx.params, - }; -}; - -posts.post('/', postsCtrl.write); -posts.get('/', postsCtrl.list); -posts.get('/:id', postsCtrl.read); -posts.patch('/:id', postsCtrl.update); -posts.delete('/:id', postsCtrl.remove); +posts.post("/", postsCtrl.write); +posts.get("/", postsCtrl.list); +posts.get("/:id", postsCtrl.read); +posts.patch("/:id", postsCtrl.update); +posts.delete("/:id", postsCtrl.remove); module.exports = posts; diff --git a/src/utils/index.js b/src/utils/index.js index 41ad5ef..51e43ce 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,5 +1,5 @@ const parseJSON = (jsonString, fallback = {}) => { - if (typeof jsonString === 'object') { + if (typeof jsonString === "object") { return jsonString; } @@ -13,32 +13,33 @@ const parseJSON = (jsonString, fallback = {}) => { }; const jwtSecret = process.env.JWT_SECRET; -const jwt = require('jsonwebtoken'); +const jwt = require("jsonwebtoken"); function decodeToken(token) { - return new Promise( - (resolve, reject) => { - jwt.verify(token, jwtSecret, (error, decoded) => { - if (error) reject(error); - resolve(decoded); - }) - }, - ) + return new Promise((resolve, reject) => { + jwt.verify(token, jwtSecret, (error, decoded) => { + console.log(error); + if (error) reject(error); + resolve(decoded); + }); + }); } async function jwtMiddleware(ctx, next) { - const token = ctx.cookies.get('access_token'); // ctx 에서 access_token 을 읽어옵니다 + const token = ctx.cookies.get("access_token"); // ctx 에서 access_token 을 읽어옵니다 + console.log("TOKEN"); + console.log(token); if (!token) return next(); // 토큰이 없으면 바로 다음 작업을 진행합니다. - try { - const decoded = await decodeToken(token); // 토큰을 디코딩 합니다 + const decoded = await decodeToken(token.toString()); // 토큰을 디코딩 합니다 // 토큰 만료일이 하루밖에 안남으면 토큰을 재발급합니다 + console.log(decoded); if (Date.now() / 1000 - decoded.iat > 60 * 60 * 24) { // 하루가 지나면 갱신해준다. const { id } = decoded; - const { generateToken } = require('../routes/auth/generateToken'); + const { generateToken } = require("../routes/auth/generateToken"); const freshToken = await generateToken({ id }); - ctx.cookies.set('access_token', freshToken, { + ctx.cookies.set("access_token", freshToken, { maxAge: 1000 * 60 * 60 * 24 * 7, // 7days httpOnly: true, }); @@ -48,7 +49,7 @@ async function jwtMiddleware(ctx, next) { ctx.request.user = decoded; } catch (e) { // token validate 실패 - ctx.request.user = null; + ctx.request.user = "ERROR"; } return next(); From 106d1d781e5c47e4e797cc8bb010207f37401486 Mon Sep 17 00:00:00 2001 From: winningarc Date: Tue, 25 Aug 2020 21:26:41 +0900 Subject: [PATCH 09/26] feat(payment): define payment model --- src/database/models/payment.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/database/models/payment.js diff --git a/src/database/models/payment.js b/src/database/models/payment.js new file mode 100644 index 0000000..920b492 --- /dev/null +++ b/src/database/models/payment.js @@ -0,0 +1,28 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + const payment = sequelize.define( + "payment", + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + ku_std_no: { + type: DataTypes.STRING, + }, + year: DataTypes.INTEGER, + semester: DataTypes.STRING, + }, + { + underscored: true, + freezeTableName: true, + charset: "utf8", + collate: "utf8_general_ci", + } + ); + payment.associate = function (models) { + // associations can be defined here + }; + return payment; +}; From 7909df25faa49d34bc296d3ccad74433186087d2 Mon Sep 17 00:00:00 2001 From: winningarc Date: Tue, 25 Aug 2020 21:26:54 +0900 Subject: [PATCH 10/26] feat(payment): add API for bulkCreate --- src/routes/admins/index.js | 18 +++++------------- src/routes/index.js | 28 +++++++++++++++------------- src/routes/payments/index.js | 9 +++++++++ src/routes/payments/payments.ctrl.js | 18 ++++++++++++++++++ src/utils/index.js | 2 -- 5 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 src/routes/payments/index.js create mode 100644 src/routes/payments/payments.ctrl.js diff --git a/src/routes/admins/index.js b/src/routes/admins/index.js index bb509cf..154cc8f 100644 --- a/src/routes/admins/index.js +++ b/src/routes/admins/index.js @@ -1,17 +1,9 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); const admins = new Router(); -const adminsCtrl = require('./admins.ctrl'); +const adminsCtrl = require("./admins.ctrl"); -const printInfo = (ctx) => { - ctx.body = { - method: ctx.method, - path: ctx.path, - params: ctx.params, - }; -}; - -admins.post('/login', adminsCtrl.login); -admins.get('/check', adminsCtrl.check); -admins.post('/register', adminsCtrl.register); +admins.post("/login", adminsCtrl.login); +admins.get("/check", adminsCtrl.check); +admins.post("/register", adminsCtrl.register); module.exports = admins; diff --git a/src/routes/index.js b/src/routes/index.js index 4c15329..41bab7e 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,21 +1,23 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); -const posts = require('./posts'); -const banners = require('./banners'); -const bulletins = require('./bulletins'); -const admins = require('./admins'); -const auth = require('./auth'); +const posts = require("./posts"); +const banners = require("./banners"); +const bulletins = require("./bulletins"); +const admins = require("./admins"); +const auth = require("./auth"); +const payments = require("./payments"); const router = new Router(); -router.get('/hello', (ctx) => { - ctx.body = 'hello'; +router.get("/hello", (ctx) => { + ctx.body = "hello"; }); -router.use('/auth', auth.routes()); -router.use('/posts', posts.routes()); -router.use('/admins', admins.routes()); -router.use('/banners', banners.routes()); -router.use('/bulletins', bulletins.routes()); +router.use("/auth", auth.routes()); +router.use("/posts", posts.routes()); +router.use("/admins", admins.routes()); +router.use("/banners", banners.routes()); +router.use("/bulletins", bulletins.routes()); +router.use("/payments", payments.routes()); module.exports = router; diff --git a/src/routes/payments/index.js b/src/routes/payments/index.js new file mode 100644 index 0000000..88df741 --- /dev/null +++ b/src/routes/payments/index.js @@ -0,0 +1,9 @@ +const Router = require("koa-router"); +const payments = new Router(); +const paymentsCtrl = require("./payments.ctrl"); + +payments.post("/", paymentsCtrl.write); +// payments.get("/", paymentsCtrl.list); +// payments.get("/:id", paymentsCtrl.read); + +module.exports = payments; diff --git a/src/routes/payments/payments.ctrl.js b/src/routes/payments/payments.ctrl.js new file mode 100644 index 0000000..8cfa373 --- /dev/null +++ b/src/routes/payments/payments.ctrl.js @@ -0,0 +1,18 @@ +const models = require("../../database/models"); +const Op = require("sequelize").Op; + +exports.write = async (ctx) => { + const { ku_std_no_list, year, semester } = ctx.request.body; + const bulkData = []; + ku_std_no_list.map((id) => { + bulkData.push({ + ku_std_no: id, + year, + semester, + }); + }); + const res = await models.payment.bulkCreate(bulkData); + if (res) { + ctx.response.body = bulkData.length; + } +}; diff --git a/src/utils/index.js b/src/utils/index.js index 51e43ce..d923b6c 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -27,8 +27,6 @@ function decodeToken(token) { async function jwtMiddleware(ctx, next) { const token = ctx.cookies.get("access_token"); // ctx 에서 access_token 을 읽어옵니다 - console.log("TOKEN"); - console.log(token); if (!token) return next(); // 토큰이 없으면 바로 다음 작업을 진행합니다. try { const decoded = await decodeToken(token.toString()); // 토큰을 디코딩 합니다 From a7ca2b772cb107d1926c761b64421e4c0ad69faf Mon Sep 17 00:00:00 2001 From: winningarc Date: Wed, 26 Aug 2020 16:53:13 +0900 Subject: [PATCH 11/26] feat(admin): manage session with cookies --- index.js | 3 -- src/config/accesstoken-strategy.js | 24 ------------- src/database/models/admin.js | 14 +++----- src/routes/admins/admins.ctrl.js | 58 ++++++++++++++++++------------ src/routes/admins/index.js | 18 +++------- src/routes/auth/auth.ctrl.js | 9 ++--- src/routes/auth/index.js | 2 +- src/routes/banners/index.js | 18 +++------- src/routes/bulletins/index.js | 25 ++++--------- src/utils/index.js | 8 ++--- 10 files changed, 62 insertions(+), 117 deletions(-) delete mode 100644 src/config/accesstoken-strategy.js diff --git a/index.js b/index.js index da42df8..84e7595 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,6 @@ const logger = require("koa-logger"); const router = require("./src/routes"); const models = require("./src/database/models/index.js"); const helmet = require("koa-helmet"); -const passport = require("koa-passport"); const swagger = require("koa2-swagger-ui"); const swaggerDoc = require("./src/utils/swaggerDef.js"); const { jwtMiddleware } = require("./src/utils"); @@ -26,8 +25,6 @@ const run = async () => { app.use(cors({ credentials: true })); app.use(helmet()); - app.use(passport.initialize()); - require("./src/config/accesstoken-strategy.js"); app.use(logger()); app.use(bodyParser()); app.use(jwtMiddleware); diff --git a/src/config/accesstoken-strategy.js b/src/config/accesstoken-strategy.js deleted file mode 100644 index ef8bcb7..0000000 --- a/src/config/accesstoken-strategy.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -const passport = require('passport'); -const TokenStrategy = require('passport-accesstoken').Strategy; -const models = require('../database/models'); - -passport.use( - new TokenStrategy(async (access_token, done) => { - try { - const admin = await models.admin.findOne({ - where: { - access_token, - }, - }); - if (!admin) - return done(null, false, { - message: 'this access token does not exist', - }); - done(null, admin); - } catch (err) { - return done(err); - } - }), -); diff --git a/src/database/models/admin.js b/src/database/models/admin.js index 14a584a..9c3d193 100644 --- a/src/database/models/admin.js +++ b/src/database/models/admin.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; module.exports = (sequelize, DataTypes) => { const admin = sequelize.define( - 'admin', + "admin", { id: { type: DataTypes.UUID, @@ -10,19 +10,15 @@ module.exports = (sequelize, DataTypes) => { }, email: DataTypes.STRING, password: DataTypes.STRING, - access_token: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - }, salt: DataTypes.STRING, }, { underscored: true, freezeTableName: true, paranoid: true, - charset: 'utf8', - collate: 'utf8_general_ci', - }, + charset: "utf8", + collate: "utf8_general_ci", + } ); admin.associate = function (models) { // associations can be defined here diff --git a/src/routes/admins/admins.ctrl.js b/src/routes/admins/admins.ctrl.js index 4bd1cb9..fddbabf 100644 --- a/src/routes/admins/admins.ctrl.js +++ b/src/routes/admins/admins.ctrl.js @@ -1,14 +1,20 @@ const models = require("../../database/models"); +const { generateToken } = require("../auth/generateToken"); const crypto = require("crypto"); -const { access } = require("fs"); -var genRandomString = function (length) { +const genRandomString = function (length) { return crypto .randomBytes(Math.ceil(length / 2)) .toString("hex") /** convert to hexadecimal format */ .slice(0, length); /** return required number of characters */ }; +const hashed = (data, salt) => { + const hash = crypto.createHmac("sha512", salt); + hash.update(data); + return hash.digest("hex"); +}; + /** @swagger * parameters: * adminAuth@header: @@ -89,13 +95,22 @@ exports.login = async (ctx) => { message: "로그인 실패!", }; } else { - const hash = crypto.createHmac("sha512", res.salt); - hash.update(password); - const value = hash.digest("hex"); + const value = hashed(password, res.salt); if (value === res.password) { + const token = await generateToken({ id: res.id }); + console.log(token); + ctx.cookies.set("kaistua_web_access_token", token, { + maxAge: 1000 * 60 * 60 * 24, + overwrite: true, + }); + ctx.status = 200; ctx.body = { - email: res.email, - accessToken: res.access_token, + auth: "admin", + }; + } else { + ctx.status = 404; + ctx.body = { + message: "로그인 실패!", }; } } @@ -133,18 +148,16 @@ exports.login = async (ctx) => { * description: Internal Server Error */ exports.check = async (ctx) => { - const url = new URLSearchParams(ctx.url.split("?")[1]); - const res = await models.admin.findOne({ - where: { access_token: url.get("access_token") }, - }); - if (!res) { + if (!ctx.request.user) { + ctx.status = 404; ctx.body = { - access: false, + message: "Unauthorized admin", + auth: false, }; } else { - ctx.body = { - access: true, - }; + const { id } = ctx.request.user; + const admin = await models.admin.findOne({ where: { id } }); + ctx.body = { auth: admin ? "admin" : false }; } }; @@ -176,9 +189,6 @@ exports.check = async (ctx) => { * id: * type: string * format: uuid - * access_token: - * type: string - * format: uuid * email: * type: string * format: email @@ -208,8 +218,10 @@ exports.register = async (ctx) => { const res = await models.admin.findOne({ where: { email } }); if (res) return; var salt = genRandomString(16); - const hash = crypto.createHmac("sha512", salt); - hash.update(password); - const value = hash.digest("hex"); - ctx.body = await models.admin.create({ email, salt, password: value }); + const value = hashed(password, salt); + ctx.response.body = await models.admin.create({ + email, + salt, + password: value, + }); }; diff --git a/src/routes/admins/index.js b/src/routes/admins/index.js index bb509cf..154cc8f 100644 --- a/src/routes/admins/index.js +++ b/src/routes/admins/index.js @@ -1,17 +1,9 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); const admins = new Router(); -const adminsCtrl = require('./admins.ctrl'); +const adminsCtrl = require("./admins.ctrl"); -const printInfo = (ctx) => { - ctx.body = { - method: ctx.method, - path: ctx.path, - params: ctx.params, - }; -}; - -admins.post('/login', adminsCtrl.login); -admins.get('/check', adminsCtrl.check); -admins.post('/register', adminsCtrl.register); +admins.post("/login", adminsCtrl.login); +admins.get("/check", adminsCtrl.check); +admins.post("/register", adminsCtrl.register); module.exports = admins; diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index e942c4f..167ca85 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -7,29 +7,26 @@ exports.signup = async (ctx) => { var record = await models.user.findOne({ where: USER_INFO }); if (record || state === process.env.REGISTER_KEY) { if (!record) { - console.log("REGISTER"); record = await models.user.create(USER_INFO); } else { - console.log("LOGIN"); } const token = await generateToken({ id: record.id }); - ctx.cookies.set("access_token", token, { + ctx.cookies.set("kaistua_web_access_token", token, { maxAge: 1000 * 60 * 60 * 24 * 7, overwrite: true, }); ctx.redirect(`${process.env.WEB_FRONTEND}/web/main`); } else { - console.log("AGREEMENT"); ctx.redirect(`${process.env.WEB_FRONTEND}/web/auth/agreement/login`); } }; exports.logout = async (ctx) => { - ctx.cookies.set("access_token", "", { overwrite: true }); + ctx.cookies.set("kaistua_web_access_token", "", { overwrite: true }); ctx.response.status = 200; }; -exports.checkUser = async (ctx) => { +exports.check = async (ctx) => { const { id } = ctx.request.user; const user = await models.user.findOne({ where: { id } }); ctx.response.body = { auth: user ? "user" : false }; diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index 5680036..2b949df 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -3,7 +3,7 @@ const auth = new Router(); const authCtrl = require("./auth.ctrl"); auth.post("/signup", authCtrl.signup); -auth.get("/checkUser", authCtrl.checkUser); +auth.get("/check", authCtrl.check); auth.get("/logout", authCtrl.logout); module.exports = auth; diff --git a/src/routes/banners/index.js b/src/routes/banners/index.js index 681c29f..895f51d 100644 --- a/src/routes/banners/index.js +++ b/src/routes/banners/index.js @@ -1,17 +1,9 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); const banners = new Router(); -const bannersCtrl = require('./banners.ctrl'); +const bannersCtrl = require("./banners.ctrl"); -const printInfo = (ctx) => { - ctx.body = { - method: ctx.method, - path: ctx.path, - params: ctx.params, - }; -}; - -banners.get('/', bannersCtrl.list); -banners.post('/', bannersCtrl.upload); -banners.delete('/:id', bannersCtrl.remove); +banners.get("/", bannersCtrl.list); +banners.post("/", bannersCtrl.upload); +banners.delete("/:id", bannersCtrl.remove); module.exports = banners; diff --git a/src/routes/bulletins/index.js b/src/routes/bulletins/index.js index 8d0400f..0bfe84f 100644 --- a/src/routes/bulletins/index.js +++ b/src/routes/bulletins/index.js @@ -1,23 +1,10 @@ -const Router = require('koa-router'); +const Router = require("koa-router"); const bulletins = new Router(); -const passport = require('koa-passport'); -const bulletinsCtrl = require('./bulletins.ctrl'); +const bulletinsCtrl = require("./bulletins.ctrl"); -bulletins.post( - '/', - passport.authenticate('token', { session: false }), - bulletinsCtrl.open, -); -bulletins.get('/', bulletinsCtrl.list); -bulletins.delete( - '/:id', - passport.authenticate('token', { session: false }), - bulletinsCtrl.close, -); -bulletins.patch( - '/:id', - passport.authenticate('token', { session: false }), - bulletinsCtrl.reopen, -); +bulletins.post("/", bulletinsCtrl.open); +bulletins.get("/", bulletinsCtrl.list); +bulletins.delete("/:id", bulletinsCtrl.close); +bulletins.patch("/:id", bulletinsCtrl.reopen); module.exports = bulletins; diff --git a/src/utils/index.js b/src/utils/index.js index 51e43ce..2983c45 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -18,7 +18,6 @@ const jwt = require("jsonwebtoken"); function decodeToken(token) { return new Promise((resolve, reject) => { jwt.verify(token, jwtSecret, (error, decoded) => { - console.log(error); if (error) reject(error); resolve(decoded); }); @@ -26,20 +25,17 @@ function decodeToken(token) { } async function jwtMiddleware(ctx, next) { - const token = ctx.cookies.get("access_token"); // ctx 에서 access_token 을 읽어옵니다 - console.log("TOKEN"); - console.log(token); + const token = ctx.cookies.get("kaistua_web_access_token"); if (!token) return next(); // 토큰이 없으면 바로 다음 작업을 진행합니다. try { const decoded = await decodeToken(token.toString()); // 토큰을 디코딩 합니다 // 토큰 만료일이 하루밖에 안남으면 토큰을 재발급합니다 - console.log(decoded); if (Date.now() / 1000 - decoded.iat > 60 * 60 * 24) { // 하루가 지나면 갱신해준다. const { id } = decoded; const { generateToken } = require("../routes/auth/generateToken"); const freshToken = await generateToken({ id }); - ctx.cookies.set("access_token", freshToken, { + ctx.cookies.set("kaistua_web_access_token", freshToken, { maxAge: 1000 * 60 * 60 * 24 * 7, // 7days httpOnly: true, }); From 3b4569b1753351ab2f4fd64d1d32144d51764f86 Mon Sep 17 00:00:00 2001 From: winningarc Date: Thu, 27 Aug 2020 12:40:46 +0900 Subject: [PATCH 12/26] fix: add cors origin --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 84e7595..78aabf9 100644 --- a/index.js +++ b/index.js @@ -23,7 +23,7 @@ const run = async () => { console.log(err); }); - app.use(cors({ credentials: true })); + app.use(cors({ credentials: true, origin: process.env.ORIGIN })); app.use(helmet()); app.use(logger()); app.use(bodyParser()); From adb636775122ab465607484caaa9cc8f9ca58f13 Mon Sep 17 00:00:00 2001 From: winningarc Date: Thu, 27 Aug 2020 12:41:07 +0900 Subject: [PATCH 13/26] fix(check): response for unauthorized --- src/routes/admins/admins.ctrl.js | 2 +- src/routes/auth/auth.ctrl.js | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/routes/admins/admins.ctrl.js b/src/routes/admins/admins.ctrl.js index fddbabf..7ac6d33 100644 --- a/src/routes/admins/admins.ctrl.js +++ b/src/routes/admins/admins.ctrl.js @@ -149,7 +149,7 @@ exports.login = async (ctx) => { */ exports.check = async (ctx) => { if (!ctx.request.user) { - ctx.status = 404; + ctx.status = 200; ctx.body = { message: "Unauthorized admin", auth: false, diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index 167ca85..0ff48cb 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -27,7 +27,26 @@ exports.logout = async (ctx) => { }; exports.check = async (ctx) => { - const { id } = ctx.request.user; - const user = await models.user.findOne({ where: { id } }); - ctx.response.body = { auth: user ? "user" : false }; + if (!ctx.request.user) { + ctx.status = 200; + ctx.body = { + message: "Unauthorized user", + auth: false, + }; + } else { + const { id } = ctx.request.user; + const user = await models.user.findOne({ where: { id } }); + if (!user) { + ctx.status = 200; + ctx.body = { + message: "Unauthorized user", + auth: false, + }; + } else { + ctx.body = { + auth: user ? "user" : false, + name: user.ku_kname || user.displayname, + }; + } + } }; From 6fc383f4d5eb85435b7a2e33bd68a6ab42015545 Mon Sep 17 00:00:00 2001 From: winningarc Date: Thu, 27 Aug 2020 22:17:44 +0900 Subject: [PATCH 14/26] feature: add payment record query --- src/routes/payments/index.js | 2 +- src/routes/payments/payments.ctrl.js | 18 ++++++++++++++++++ src/utils/index.js | 1 - 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/routes/payments/index.js b/src/routes/payments/index.js index 88df741..30e00da 100644 --- a/src/routes/payments/index.js +++ b/src/routes/payments/index.js @@ -3,7 +3,7 @@ const payments = new Router(); const paymentsCtrl = require("./payments.ctrl"); payments.post("/", paymentsCtrl.write); -// payments.get("/", paymentsCtrl.list); +payments.get("/", paymentsCtrl.list); // payments.get("/:id", paymentsCtrl.read); module.exports = payments; diff --git a/src/routes/payments/payments.ctrl.js b/src/routes/payments/payments.ctrl.js index 8cfa373..4ed279e 100644 --- a/src/routes/payments/payments.ctrl.js +++ b/src/routes/payments/payments.ctrl.js @@ -16,3 +16,21 @@ exports.write = async (ctx) => { ctx.response.body = bulkData.length; } }; + +exports.list = async (ctx) => { + if (ctx.request.user) { + const { id } = ctx.request.user; + const user = await models.user.findOne({ where: { id } }); + console.log(user.ku_std_no); + const res = await models.payment.findAll({ + where: { ku_std_no: user.ku_std_no }, + }); + if (res) { + ctx.body = { payments: res }; + } else { + ctx.body = { payments: [] }; + } + } else { + ctx.body = { payments: [] }; + } +}; diff --git a/src/utils/index.js b/src/utils/index.js index 2983c45..ff8ee61 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -40,7 +40,6 @@ async function jwtMiddleware(ctx, next) { httpOnly: true, }); } - // ctx.request.user 에 디코딩된 값을 넣어줍니다 ctx.request.user = decoded; } catch (e) { From 140d1ea91dcbb52e7b0a47e5963b769dcade46fe Mon Sep 17 00:00:00 2001 From: winningarc Date: Fri, 28 Aug 2020 12:06:51 +0900 Subject: [PATCH 15/26] feat(sequelize): redesign database with migrations --- config/config.js | 28 ++++ .../migrations/20200827223319-create-admin.js | 22 +++ .../20200827223527-create-banner.js | 20 +++ .../migrations/20200827223657-create-board.js | 21 +++ .../20200827223837-create-cancel-request.js | 21 +++ .../20200827223935-create-payment.js | 20 +++ .../migrations/20200827224019-create-post.js | 29 ++++ .../20200827224111-create-student.js | 24 ++++ .../20200827230222-create-associations.js | 76 +++++++++++ src/database/models/Board.js | 29 ++++ src/database/models/CancelRequest.js | 28 ++++ src/database/models/Student.js | 32 +++++ src/database/models/admin.js | 10 +- src/database/models/banner.js | 25 ++-- src/database/models/bulletin.js | 35 ----- src/database/models/cancel_request.js | 29 ---- src/database/models/index.js | 20 +-- src/database/models/payment.js | 15 +-- src/database/models/post.js | 51 ++++--- src/database/models/user.js | 30 ----- src/routes/admins/admins.ctrl.js | 69 ++++------ src/routes/auth/auth.ctrl.js | 58 ++++---- src/routes/banners/banners.ctrl.js | 56 ++------ .../boards.ctrl.js} | 122 +++++++---------- src/routes/boards/index.js | 10 ++ src/routes/bulletins/index.js | 10 -- .../cancelRequest/cancelRequest.ctrl.js | 125 ++++++++---------- src/routes/cancelRequest/index.js | 8 +- src/routes/index.js | 4 +- src/routes/payments/payments.ctrl.js | 38 +++--- src/routes/posts/posts.ctrl.js | 77 ++++++----- src/utils/index.js | 4 +- 32 files changed, 662 insertions(+), 484 deletions(-) create mode 100644 config/config.js create mode 100644 src/database/migrations/20200827223319-create-admin.js create mode 100644 src/database/migrations/20200827223527-create-banner.js create mode 100644 src/database/migrations/20200827223657-create-board.js create mode 100644 src/database/migrations/20200827223837-create-cancel-request.js create mode 100644 src/database/migrations/20200827223935-create-payment.js create mode 100644 src/database/migrations/20200827224019-create-post.js create mode 100644 src/database/migrations/20200827224111-create-student.js create mode 100644 src/database/migrations/20200827230222-create-associations.js create mode 100644 src/database/models/Board.js create mode 100644 src/database/models/CancelRequest.js create mode 100644 src/database/models/Student.js delete mode 100644 src/database/models/bulletin.js delete mode 100644 src/database/models/cancel_request.js delete mode 100644 src/database/models/user.js rename src/routes/{bulletins/bulletins.ctrl.js => boards/boards.ctrl.js} (70%) create mode 100644 src/routes/boards/index.js delete mode 100644 src/routes/bulletins/index.js diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..ee8a262 --- /dev/null +++ b/config/config.js @@ -0,0 +1,28 @@ +require("dotenv").config(); + +module.exports = { + development: { + username: process.env.USERNAME, + password: process.env.PASSWORD, + database: process.env.DATABASE, + host: process.env.HOST, + dialect: "mysql", + operatorsAliases: 0, + }, + test: { + username: process.env.USERNAME, + password: process.env.PASSWORD, + database: process.env.DATABASE, + host: process.env.HOST, + dialect: "mysql", + operatorsAliases: 0, + }, + production: { + username: process.env.USERNAME, + password: process.env.PASSWORD, + database: process.env.DATABASE, + host: process.env.HOST, + dialect: "mysql", + operatorsAliases: 0, + }, +}; diff --git a/src/database/migrations/20200827223319-create-admin.js b/src/database/migrations/20200827223319-create-admin.js new file mode 100644 index 0000000..5e125d1 --- /dev/null +++ b/src/database/migrations/20200827223319-create-admin.js @@ -0,0 +1,22 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("Admin", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + email: Sequelize.STRING, + password: Sequelize.STRING, + salt: Sequelize.STRING, + createdAt: Sequelize.DATE, + updatedAt: Sequelize.DATE, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Admin"); + }, +}; diff --git a/src/database/migrations/20200827223527-create-banner.js b/src/database/migrations/20200827223527-create-banner.js new file mode 100644 index 0000000..9e098d0 --- /dev/null +++ b/src/database/migrations/20200827223527-create-banner.js @@ -0,0 +1,20 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("Banner", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + image: Sequelize.TEXT, + link: Sequelize.TEXT, + isActive: Sequelize.BOOLEAN, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Banner"); + }, +}; diff --git a/src/database/migrations/20200827223657-create-board.js b/src/database/migrations/20200827223657-create-board.js new file mode 100644 index 0000000..0d1c521 --- /dev/null +++ b/src/database/migrations/20200827223657-create-board.js @@ -0,0 +1,21 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("Board", { + id: { + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + korTitle: Sequelize.STRING, + engTitle: Sequelize.STRING, + korDescription: Sequelize.TEXT, + engDescription: Sequelize.TEXT, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Board"); + }, +}; diff --git a/src/database/migrations/20200827223837-create-cancel-request.js b/src/database/migrations/20200827223837-create-cancel-request.js new file mode 100644 index 0000000..2d95435 --- /dev/null +++ b/src/database/migrations/20200827223837-create-cancel-request.js @@ -0,0 +1,21 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("CancelRequest", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + year: Sequelize.INTEGER, + semester: Sequelize.STRING, + createdAt: Sequelize.DATE, + updatedAt: Sequelize.DATE, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("CancelRequest"); + }, +}; diff --git a/src/database/migrations/20200827223935-create-payment.js b/src/database/migrations/20200827223935-create-payment.js new file mode 100644 index 0000000..7b11446 --- /dev/null +++ b/src/database/migrations/20200827223935-create-payment.js @@ -0,0 +1,20 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("Payment", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + studentNumber: Sequelize.STRING, + year: Sequelize.INTEGER, + semester: Sequelize.STRING, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Payment"); + }, +}; diff --git a/src/database/migrations/20200827224019-create-post.js b/src/database/migrations/20200827224019-create-post.js new file mode 100644 index 0000000..d71564d --- /dev/null +++ b/src/database/migrations/20200827224019-create-post.js @@ -0,0 +1,29 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("Post", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + author: Sequelize.TEXT, + korTitle: Sequelize.TEXT, + engTitle: Sequelize.TEXT, + korContent: Sequelize.TEXT, + korContent: Sequelize.TEXT, + views: { + type: Sequelize.INTEGER, + defaultValue: 0, + }, + isActive: Sequelize.BOOLEAN, + createdAt: Sequelize.DATE, + updatedAt: Sequelize.DATE, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Post"); + }, +}; diff --git a/src/database/migrations/20200827224111-create-student.js b/src/database/migrations/20200827224111-create-student.js new file mode 100644 index 0000000..506634e --- /dev/null +++ b/src/database/migrations/20200827224111-create-student.js @@ -0,0 +1,24 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable("Student", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + studentNumber: { type: Sequelize.INTEGER, unique: true }, + kaistUid: Sequelize.STRING, + korName: Sequelize.STRING, + engName: Sequelize.STRING, + affiliation: Sequelize.STRING, + createdAt: Sequelize.DATE, + updatedAt: Sequelize.DATE, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Student"); + }, +}; diff --git a/src/database/migrations/20200827230222-create-associations.js b/src/database/migrations/20200827230222-create-associations.js new file mode 100644 index 0000000..b5af2fb --- /dev/null +++ b/src/database/migrations/20200827230222-create-associations.js @@ -0,0 +1,76 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + // Board hasMany Post + return queryInterface + .addColumn( + "Post", // name of Source model + "BoardId", // name of the key we're adding + { + type: Sequelize.INTEGER, + references: { + model: "Board", // name of Target model + key: "id", // key in Target model that we're referencing + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + } + ) + .then(() => { + // Student hasMany CancelRequest + return queryInterface.addColumn( + "CancelRequest", // name of Target model + "studentNumber", // name of the key we're adding + { + type: Sequelize.INTEGER, + references: { + model: "Student", // name of Source model + key: "studentNumber", + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + } + ); + }) + .then(() => { + // Student hasMany Payment + return queryInterface.addColumn( + "Payment", // name of Target model + "studentId", // name of the key we're adding + { + type: Sequelize.UUID, + references: { + model: "Student", // name of Source model + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + } + ); + }); + }, + + down: async (queryInterface, Sequelize) => { + // remove Board hasMany Post + return queryInterface + .removeColumn( + "Post", // name of Source model + "BoardId" // key we want to remove + ) + .then(() => { + // remove Student hasMany CancelRequest + return queryInterface.removeColumn( + "CancelRequest", // name of the Target model + "studentNumber" // key we want to remove + ); + }) + .then(() => { + // remove Student hasMany Payment + return queryInterface.removeColumn( + "Payment", // name of the Target model + "studentId" // key we want to remove + ); + }); + }, +}; diff --git a/src/database/models/Board.js b/src/database/models/Board.js new file mode 100644 index 0000000..d0fb462 --- /dev/null +++ b/src/database/models/Board.js @@ -0,0 +1,29 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + const Board = sequelize.define( + "Board", + { + id: { + autoIncrement: true, + primaryKey: true, + type: DataTypes.INTEGER, + }, + korTitle: DataTypes.STRING, + engTitle: DataTypes.STRING, + korDescription: DataTypes.TEXT, + engDescription: DataTypes.TEXT, + }, + { + freezeTableName: true, + timestamps: false, + charset: "utf8", + collate: "utf8_general_ci", + } + ); + + Board.associate = function (models) { + models.Board.hasMany(models.Post); + }; + + return Board; +}; diff --git a/src/database/models/CancelRequest.js b/src/database/models/CancelRequest.js new file mode 100644 index 0000000..59361eb --- /dev/null +++ b/src/database/models/CancelRequest.js @@ -0,0 +1,28 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + const CancelRequest = sequelize.define( + "CancelRequest", + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + year: DataTypes.INTEGER, + semester: DataTypes.STRING, + }, + { + freezeTableName: true, + charset: "utf8", + collate: "utf8_general_ci", + } + ); + CancelRequest.associate = function (models) { + // associations can be defined here + models.CancelRequest.belongsTo(models.Student, { + targetKey: "studentNumber", + foreignKey: "studentNumber", + }); + }; + return CancelRequest; +}; diff --git a/src/database/models/Student.js b/src/database/models/Student.js new file mode 100644 index 0000000..94a6a8b --- /dev/null +++ b/src/database/models/Student.js @@ -0,0 +1,32 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + const Student = sequelize.define( + "Student", + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + studentNumber: DataTypes.INTEGER, + kaistUid: DataTypes.STRING, + korName: DataTypes.STRING, + engName: DataTypes.STRING, + affiliation: DataTypes.STRING, + }, + { + freezeTableName: true, + charset: "utf8", + collate: "utf8_general_ci", + } + ); + Student.associate = function (models) { + // associations can be defined here + Student.hasMany(models.CancelRequest, { + targetKey: "studentNumber", + foreignKey: "studentNumber", + }); + Student.hasMany(models.Payment); + }; + return Student; +}; diff --git a/src/database/models/admin.js b/src/database/models/admin.js index 9c3d193..1aa08ac 100644 --- a/src/database/models/admin.js +++ b/src/database/models/admin.js @@ -1,7 +1,7 @@ "use strict"; module.exports = (sequelize, DataTypes) => { - const admin = sequelize.define( - "admin", + const Admin = sequelize.define( + "Admin", { id: { type: DataTypes.UUID, @@ -13,15 +13,13 @@ module.exports = (sequelize, DataTypes) => { salt: DataTypes.STRING, }, { - underscored: true, freezeTableName: true, - paranoid: true, charset: "utf8", collate: "utf8_general_ci", } ); - admin.associate = function (models) { + Admin.associate = function (models) { // associations can be defined here }; - return admin; + return Admin; }; diff --git a/src/database/models/banner.js b/src/database/models/banner.js index 599c40e..dad7d15 100644 --- a/src/database/models/banner.js +++ b/src/database/models/banner.js @@ -1,27 +1,26 @@ -'use strict'; +"use strict"; module.exports = (sequelize, DataTypes) => { - const banner = sequelize.define( - 'banner', + const Banner = sequelize.define( + "Banner", { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, }, - url: DataTypes.STRING, - link: DataTypes.STRING, + image: DataTypes.TEXT, + link: DataTypes.TEXT, + isActive: DataTypes.BOOLEAN, }, { - underscored: true, - paranoid: true, freezeTableName: true, - charset: 'utf8', - collate: 'utf8_general_ci', - }, + timestamps: false, + charset: "utf8", + collate: "utf8_general_ci", + } ); - banner.associate = function (models) { + Banner.associate = function (models) { // associations can be defined here }; - banner.sync({ force: true }); - return banner; + return Banner; }; diff --git a/src/database/models/bulletin.js b/src/database/models/bulletin.js deleted file mode 100644 index 88159e3..0000000 --- a/src/database/models/bulletin.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; -module.exports = (sequelize, DataTypes) => { - const bulletin = sequelize.define( - 'bulletin', - { - id: { - allowNull: false, - autoIncrement: true, - primaryKey: true, - type: DataTypes.INTEGER, - }, - title: { - type: DataTypes.TEXT, - allowNull: false, - }, - description: { - type: DataTypes.TEXT, - allowNull: false, - }, - }, - { - underscored: true, - freezeTableName: true, - paranoid: true, - charset: 'utf8', - collate: 'utf8_general_ci', - }, - ); - - bulletin.associate = function (models) { - models.bulletin.hasMany(models.post); - }; - - return bulletin; -}; diff --git a/src/database/models/cancel_request.js b/src/database/models/cancel_request.js deleted file mode 100644 index f20ff97..0000000 --- a/src/database/models/cancel_request.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -module.exports = (sequelize, DataTypes) => { - const cancel_request = sequelize.define( - "cancel_request", - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - ku_std_no: DataTypes.STRING, - displayname: DataTypes.STRING, - ku_kname: DataTypes.STRING, - }, - { - underscored: true, - freezeTableName: true, - charset: "utf8", - collate: "utf8_general_ci", - } - ); - cancel_request.associate = function (models) { - // associations can be defined here - models.cancel_request.belongsTo(models.user, { - foreignKey: "id" - }) - }; - return cancel_request; -}; diff --git a/src/database/models/index.js b/src/database/models/index.js index 6a8ec48..6f36b4a 100644 --- a/src/database/models/index.js +++ b/src/database/models/index.js @@ -1,30 +1,32 @@ -'use strict'; +"use strict"; -const fs = require('fs'); -const path = require('path'); -const Sequelize = require('sequelize'); +const fs = require("fs"); +const path = require("path"); +const Sequelize = require("sequelize"); const basename = path.basename(__filename); const db = {}; -let sequelize; -sequelize = new Sequelize( +const sequelize = new Sequelize( process.env.DATABASE, process.env.USERNAME, process.env.PASSWORD, { host: process.env.HOST, dialect: process.env.DIALECT, - }, + } ); fs.readdirSync(__dirname) .filter((file) => { return ( - file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js' + file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js" ); }) .forEach((file) => { - const model = sequelize['import'](path.join(__dirname, file)); + const model = require(path.join(__dirname, file))( + sequelize, + Sequelize.DataTypes + ); db[model.name] = model; }); diff --git a/src/database/models/payment.js b/src/database/models/payment.js index 920b492..0eb32e8 100644 --- a/src/database/models/payment.js +++ b/src/database/models/payment.js @@ -1,28 +1,27 @@ "use strict"; module.exports = (sequelize, DataTypes) => { - const payment = sequelize.define( - "payment", + const Payment = sequelize.define( + "Payment", { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, }, - ku_std_no: { - type: DataTypes.STRING, - }, + studentNumber: DataTypes.STRING, year: DataTypes.INTEGER, semester: DataTypes.STRING, }, { - underscored: true, freezeTableName: true, + timestamps: false, charset: "utf8", collate: "utf8_general_ci", } ); - payment.associate = function (models) { + Payment.associate = function (models) { // associations can be defined here + models.Payment.belongsTo(models.Student); }; - return payment; + return Payment; }; diff --git a/src/database/models/post.js b/src/database/models/post.js index 6cc80b6..c52399a 100644 --- a/src/database/models/post.js +++ b/src/database/models/post.js @@ -1,49 +1,44 @@ -'use strict'; +"use strict"; module.exports = (sequelize, DataTypes) => { - const post = sequelize.define( - 'post', + const Post = sequelize.define( + "Post", { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, }, - title: { - type: DataTypes.TEXT, - allowNull: false, - }, - author: { - type: DataTypes.TEXT, - allowNull: false, - }, - content: { - type: DataTypes.TEXT, - allowNull: false, - }, + author: DataTypes.TEXT, + korTitle: DataTypes.TEXT, + engTitle: DataTypes.TEXT, + korContent: DataTypes.TEXT, + korContent: DataTypes.TEXT, views: { type: DataTypes.INTEGER, defaultValue: 0, }, - bulletin_id: { - type: DataTypes.INTEGER, - allowNull: false, + isActive: DataTypes.BOOLEAN, + isNew: { + type: DataTypes.BOOLEAN, + get: function () { + const createdAt = this.getDataValue("createdAt"); + const createdAtDate = new Date(createdAt); + const now = new Date(); + return createdAtDate.getMinutes() > now.getMinutes() - 60 * 24; + }, }, }, { - underscored: true, freezeTableName: true, paranoid: true, - charset: 'utf8', - collate: 'utf8_general_ci', - }, + charset: "utf8", + collate: "utf8_general_ci", + } ); - post.associate = function (models) { - models.post.belongsTo(models.bulletin, { - foreignKey: 'bulletin_id', - onDelete: 'cascade', - }); + Post.associate = function (models) { + models.Post.belongsTo(models.Board); }; - return post; + return Post; }; diff --git a/src/database/models/user.js b/src/database/models/user.js deleted file mode 100644 index cbf8c85..0000000 --- a/src/database/models/user.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -module.exports = (sequelize, DataTypes) => { - const user = sequelize.define( - "user", - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - ku_std_no: DataTypes.STRING, - kaist_uid: DataTypes.STRING, - ku_employee_number: DataTypes.STRING, - displayname: DataTypes.STRING, - ku_acad_name: DataTypes.STRING, - ku_kname: DataTypes.STRING, - }, - { - underscored: true, - freezeTableName: true, - paranoid: true, - charset: "utf8", - collate: "utf8_general_ci", - } - ); - user.associate = function (models) { - // associations can be defined here - }; - return user; -}; diff --git a/src/routes/admins/admins.ctrl.js b/src/routes/admins/admins.ctrl.js index 7ac6d33..7ad66bb 100644 --- a/src/routes/admins/admins.ctrl.js +++ b/src/routes/admins/admins.ctrl.js @@ -1,6 +1,7 @@ const models = require("../../database/models"); const { generateToken } = require("../auth/generateToken"); const crypto = require("crypto"); +const { assert } = require("console"); const genRandomString = function (length) { return crypto @@ -77,43 +78,24 @@ const hashed = (data, salt) => { * description: Unauthorized * 404: * description: Not Found (Failed to login) - * schema: - * type: object - * properties: - * message: - * type: string - * example: 로그인 실패! * 500: * description: Internal Server Error */ exports.login = async (ctx) => { const { email, password } = ctx.request.body; - const res = await models.admin.findOne({ where: { email } }); - if (!res) { - ctx.status = 404; - ctx.body = { - message: "로그인 실패!", - }; - } else { - const value = hashed(password, res.salt); - if (value === res.password) { - const token = await generateToken({ id: res.id }); - console.log(token); - ctx.cookies.set("kaistua_web_access_token", token, { - maxAge: 1000 * 60 * 60 * 24, - overwrite: true, - }); - ctx.status = 200; - ctx.body = { - auth: "admin", - }; - } else { - ctx.status = 404; - ctx.body = { - message: "로그인 실패!", - }; - } - } + const res = await models.Admin.findOne({ where: { email } }); + ctx.assert(res, 204); + const value = hashed(password, res.salt); + ctx.assert(value === res.password, 204); + const token = await generateToken({ id: res.id }); + ctx.cookies.set(process.env.ACCESS_TOKEN, token, { + maxAge: 1000 * 60 * 60 * 24, + overwrite: true, + }); + ctx.status = 200; + ctx.body = { + auth: "admin", + }; }; /** @swagger @@ -148,17 +130,12 @@ exports.login = async (ctx) => { * description: Internal Server Error */ exports.check = async (ctx) => { - if (!ctx.request.user) { - ctx.status = 200; - ctx.body = { - message: "Unauthorized admin", - auth: false, - }; - } else { - const { id } = ctx.request.user; - const admin = await models.admin.findOne({ where: { id } }); - ctx.body = { auth: admin ? "admin" : false }; - } + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const admin = await models.Admin.findOne({ where: { id } }); + ctx.assert(admin, 401, "Test"); + ctx.status = 200; + ctx.body = { auth: "admin" }; }; /** @swagger @@ -215,11 +192,11 @@ exports.check = async (ctx) => { */ exports.register = async (ctx) => { const { email, password } = ctx.request.body; - const res = await models.admin.findOne({ where: { email } }); - if (res) return; + const res = await models.Admin.findOne({ where: { email } }); + ctx.assert(!res, 400); var salt = genRandomString(16); const value = hashed(password, salt); - ctx.response.body = await models.admin.create({ + ctx.response.body = await models.Admin.create({ email, salt, password: value, diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index 0ff48cb..bee69a5 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -4,14 +4,32 @@ const e = require("cors"); exports.signup = async (ctx) => { const { USER_INFO, state } = JSON.parse(ctx.request.body.result).dataMap; - var record = await models.user.findOne({ where: USER_INFO }); + const newStudent = { + studentNumber: USER_INFO.ku_std_no, + kaistUid: USER_INFO.kaist_uid, + korName: USER_INFO.ku_kname, + engName: USER_INFO.displayname, + affiliation: USER_INFO.ku_acad_name, + }; + var record = await models.Student.findOne({ where: newStudent }); if (record || state === process.env.REGISTER_KEY) { if (!record) { - record = await models.user.create(USER_INFO); + record = await models.Student.create(newStudent); + const studentId = record.id; + const payments = await models.Payment.findAll({ + where: { studentNumber: record.studentNumber }, + }); + console.log(payments); + await Promise.all( + payments.map(async (payment) => { + payment.StudentId = studentId; + await payment.save(); + }) + ); } else { } const token = await generateToken({ id: record.id }); - ctx.cookies.set("kaistua_web_access_token", token, { + ctx.cookies.set(process.env.ACCESS_TOKEN, token, { maxAge: 1000 * 60 * 60 * 24 * 7, overwrite: true, }); @@ -22,31 +40,17 @@ exports.signup = async (ctx) => { }; exports.logout = async (ctx) => { - ctx.cookies.set("kaistua_web_access_token", "", { overwrite: true }); - ctx.response.status = 200; + ctx.cookies.set(process.env.ACCESS_TOKEN, "", { overwrite: true }); + ctx.status = 200; }; exports.check = async (ctx) => { - if (!ctx.request.user) { - ctx.status = 200; - ctx.body = { - message: "Unauthorized user", - auth: false, - }; - } else { - const { id } = ctx.request.user; - const user = await models.user.findOne({ where: { id } }); - if (!user) { - ctx.status = 200; - ctx.body = { - message: "Unauthorized user", - auth: false, - }; - } else { - ctx.body = { - auth: user ? "user" : false, - name: user.ku_kname || user.displayname, - }; - } - } + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const student = await models.Student.findOne({ where: { id } }); + ctx.assert(student, 401); + ctx.body = { + auth: "student", + name: student.korName || student.engName, + }; }; diff --git a/src/routes/banners/banners.ctrl.js b/src/routes/banners/banners.ctrl.js index 3c8e7c2..70edecf 100644 --- a/src/routes/banners/banners.ctrl.js +++ b/src/routes/banners/banners.ctrl.js @@ -1,4 +1,4 @@ -const models = require('../../database/models'); +const models = require("../../database/models"); /** @swagger * /banners: @@ -48,20 +48,9 @@ const models = require('../../database/models'); * description: Internal Server Error */ exports.upload = async (ctx) => { - const { url, link } = ctx.request.body; - const banner = { - url: url, - link: link, - }; - await models.banner - .create(banner) - .then((res) => { - console.log('배너 추가 성공!'); - ctx.body = res; - }) - .catch((err) => { - console.log(err); - }); + const { image, link, isActive } = ctx.request.body; + const res = await models.Banner.create({ image, link, isActive }); + ctx.assert(res, 400); }; /** @swagger @@ -106,15 +95,9 @@ exports.upload = async (ctx) => { * description: Internal Server Error */ exports.list = async (ctx) => { - await models.banner - .findAll() - .then((res) => { - const banners = res; - ctx.body = banners; - }) - .catch((err) => { - console.log(err); - }); + const banners = await models.Banner.findAll({ where: { isActive: true } }); + ctx.assert(banners, 404); + ctx.body = banners; }; /** @swagger @@ -152,23 +135,10 @@ exports.list = async (ctx) => { exports.remove = async (ctx) => { const { id } = ctx.params; - await models.banner - .destroy({ - where: { id: id }, - }) - .then((res) => { - //number - if (!res) { - ctx.status = 404; - ctx.body = { - message: '배너가 존재하지 않습니다.', - }; - } else { - console.log('배너 삭제 성공!'); - ctx.status = 204; - } - }) - .catch((err) => { - console.log(err); - }); + const banner = await models.Banner.findOne({ + where: { id: id }, + }); + ctx.assert(banner, 404); + banner.destroy(); + ctx.status = 204; }; diff --git a/src/routes/bulletins/bulletins.ctrl.js b/src/routes/boards/boards.ctrl.js similarity index 70% rename from src/routes/bulletins/bulletins.ctrl.js rename to src/routes/boards/boards.ctrl.js index ac4eb69..cdd2d03 100644 --- a/src/routes/bulletins/bulletins.ctrl.js +++ b/src/routes/boards/boards.ctrl.js @@ -1,15 +1,14 @@ -const models = require('../../database/models'); - +const models = require("../../database/models"); /** @swagger - * /bulletins: + * /boards: * post: - * summary: open bulletin - * tags: [Bulletins] + * summary: create board + * tags: [Boards] * parameters: * - $ref: "#/parameters/adminAuth@header" * - in: body - * name: bulletin + * name: board * schema: * type: object * properties: @@ -47,28 +46,27 @@ const models = require('../../database/models'); * 500: * description: Internal Server Error */ -exports.open = async (ctx) => { - const { title, description } = ctx.request.body; - const bulletin = { - title: title, - description: description, - }; - await models.bulletin - .create(bulletin) - .then((res) => { - console.log('게시판 오픈 성공!'); - ctx.body = res; - }) - .catch((err) => { - console.log(err); - }); +exports.create = async (ctx) => { + const { + korTitle, + engTitle, + korDescription, + engDescription, + } = ctx.request.body; + const board = { korTitle, engTitle, korDescription, engDescription }; + const res = await models.Board.create(board); + + ctx.assert(res, 400); + + ctx.status = 204; + ctx.body = res; }; /** @swagger - * /bulletins: + * /boards: * get: - * summary: obtain all bulletins - * tags: [Bulletins] + * summary: obtain all boards + * tags: [Boards] * produces: * - application/json * responses: @@ -107,22 +105,16 @@ exports.open = async (ctx) => { * description: Internal Server Error */ exports.list = async (ctx) => { - await models.bulletin - .findAll() - .then((res) => { - const bulletins = res; - ctx.body = bulletins; - }) - .catch((err) => { - console.log(err); - }); + const res = models.Board.findAll(); + ctx.assert(res, 404); + ctx.body = res; }; /** @swagger - * /bulletins/{id}: + * /boards/{id}: * delete: - * summary: delete bulletin by ID - * tags: [Bulletins] + * summary: delete board by ID + * tags: [Boards] * parameters: * - $ref: "#/parameters/adminAuth@header" * - in: path @@ -140,7 +132,7 @@ exports.list = async (ctx) => { * 401: * description: Unauthorized * 404: - * description: Not Found (bulletin doesn't exist) + * description: Not Found (board doesn't exist) * schema: * type: object * properties: @@ -150,31 +142,24 @@ exports.list = async (ctx) => { * 500: * description: Internal Server Error */ -exports.close = async (ctx) => { +exports.delete = async (ctx) => { const { id } = ctx.params; - - await models.bulletin - .destroy({ - where: { id: id }, - }) - .then((res) => { - if (!res) { - ctx.status = 404; - ctx.body = { - message: '게시판이 존재하지 않습니다!', - }; - } else { - console.log('게시판 삭제 성공!'); - ctx.status = 204; - } - }); + ctx.assert(id, 400); + const res = await models.Board.findOne({ + where: { + id, + }, + }); + assert(res, 404); + res.destroy(); + ctx.status = 204; }; /** @swagger - * /bulletins/{id}: + * /boards/{id}: * patch: - * summary: update title or description of bulletin - * tags: [Bulletins] + * summary: update title or description of board + * tags: [Boards] * parameters: * - $ref: "#/parameters/adminAuth@header" * - in: path @@ -183,7 +168,7 @@ exports.close = async (ctx) => { * type: string * required: true * - in: body - * name: bulletin + * name: board * schema: * type: object * properties: @@ -213,23 +198,18 @@ exports.close = async (ctx) => { * 500: * description: Internal Server Error */ -exports.reopen = async (ctx) => { +exports.edit = async (ctx) => { const { id } = ctx.params; const { title, description } = ctx.request.body; - const bulletin = { + const board = { title: title, description: description, }; - await models.bulletin - .update(bulletin, { - where: { id: id }, - }) - .then((res) => { - ctx.body = bulletin; - console.log('게시판 업데이트 성공!'); - }) - .catch((err) => { - console.log(err); - }); + const res = await models.Board.update(board, { + where: { id }, + }); + ctx.assert(res, 404); + ctx.status = 200; + ctx.body = res; }; diff --git a/src/routes/boards/index.js b/src/routes/boards/index.js new file mode 100644 index 0000000..087109d --- /dev/null +++ b/src/routes/boards/index.js @@ -0,0 +1,10 @@ +const Router = require("koa-router"); +const boards = new Router(); +const boardsCtrl = require("./boards.ctrl"); + +boards.post("/", boardsCtrl.create); +boards.get("/", boardsCtrl.list); +boards.delete("/:id", boardsCtrl.delete); +boards.patch("/:id", boardsCtrl.edit); + +module.exports = boards; diff --git a/src/routes/bulletins/index.js b/src/routes/bulletins/index.js deleted file mode 100644 index 0bfe84f..0000000 --- a/src/routes/bulletins/index.js +++ /dev/null @@ -1,10 +0,0 @@ -const Router = require("koa-router"); -const bulletins = new Router(); -const bulletinsCtrl = require("./bulletins.ctrl"); - -bulletins.post("/", bulletinsCtrl.open); -bulletins.get("/", bulletinsCtrl.list); -bulletins.delete("/:id", bulletinsCtrl.close); -bulletins.patch("/:id", bulletinsCtrl.reopen); - -module.exports = bulletins; diff --git a/src/routes/cancelRequest/cancelRequest.ctrl.js b/src/routes/cancelRequest/cancelRequest.ctrl.js index c5b1db2..a5c9920 100644 --- a/src/routes/cancelRequest/cancelRequest.ctrl.js +++ b/src/routes/cancelRequest/cancelRequest.ctrl.js @@ -3,89 +3,76 @@ const Op = require("sequelize").Op; /** * POST /cancelRequest - * {id} + * { year, semester } */ -exports.write = async (ctx) => { - const { id } = ctx.request.body; - const res = await models.user.findOne({ +exports.post = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const student = await models.Student.findOne({ where: { id }, - }) - if (!res) ctx.body = "No user found"; - console.log(res.ku_std_no) - const { ku_std_no, displayname, ku_kname } = res; - await models.cancel_request - .create({ id, ku_std_no, displayname, ku_kname }) - .then((res) => { - ctx.body = res; - }) - .catch((err) => { - console.log(err); - }); + }); + ctx.assert(student, 401); + const { year, semester } = ctx.request.body; + const { studentNumber, korName, engName } = student; + const res = await models.CancelRequest.create({ + studentNumber, + korName, + engName, + year, + semester, + }); + ctx.assert(res, 400); }; /** - * GET /cancelRequest + * GET /cancelRequest/admin */ - -exports.list = async (ctx) => { - await models.cancel_request - .findAll({ - order: [["ku_std_no", "ASC"]], - }) - .then((res) => { - ctx.body = res; - }) - .catch((err) => { - console.log(err); - }); +exports.getAll = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const admin = await models.Admin.findOne({ + where: { id }, + }); + ctx.assert(admin, 401); + const res = await models.CancelRequest.findAll({ + order: [["ku_std_no", "ASC"]], + }); + ctx.assert(res, 404); + ctx.body = res; }; /** - * GET /cancelRequest/:id + * GET /cancelRequest */ -exports.read = async (ctx) => { - const { id } = ctx.params; +exports.getOne = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const student = await models.Student.findOne({ + where: { id }, + include: models.CancelRequest, + }); + ctx.assert(student, 401); - await models.cancel_request - .findOne({ - where: { id }, - }) - .then((res) => { - if (!res) - ctx.body = { exists: false }; - else - ctx.body = { exists: true }; - }) - .catch((err) => { - console.log(err) - ctx.body = { exists: false }; - }); + if (student.CancelRequest) { + ctx.body = { exists: true }; + } else { + ctx.body = { exists: true }; + } }; /** - * DELETE /cancelRequest/:id + * DELETE /cancelRequest */ -exports.remove = async (ctx) => { - const { id } = ctx.params; - - await models.cancel_request - .destroy({ - where: { id: id }, - }) - .then((res) => { - if (!res) { - ctx.status = 404; - ctx.body = { - message: "id가 존재하지 않습니다.", - }; - } else { - console.log("cancel request 삭제 성공!"); - ctx.status = 204; - } - }) - .catch((err) => { - console.log(err); - }); -}; \ No newline at end of file +exports.delete = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const { year, semester } = ctx.request.params; + const student = await models.Student.findOne({ + where: { id }, + include: { model: models.CancelRequest, where: { year, semester } }, + }); + ctx.assert(student, 401); + ctx.body = student.CancelRequests[0].destroy(); +}; diff --git a/src/routes/cancelRequest/index.js b/src/routes/cancelRequest/index.js index 62aa5d1..a80955a 100644 --- a/src/routes/cancelRequest/index.js +++ b/src/routes/cancelRequest/index.js @@ -2,9 +2,9 @@ const Router = require("koa-router"); const cancelRequest = new Router(); const cancelRequestCtrl = require("./cancelRequest.ctrl"); -cancelRequest.post("/", cancelRequestCtrl.write); -cancelRequest.get("/", cancelRequestCtrl.list); -cancelRequest.get("/:id", cancelRequestCtrl.read); -cancelRequest.delete("/:id", cancelRequestCtrl.remove); +cancelRequest.post("/", cancelRequestCtrl.post); +cancelRequest.get("/admin", cancelRequestCtrl.getAll); +cancelRequest.get("/", cancelRequestCtrl.getOne); +cancelRequest.delete("/", cancelRequestCtrl.delete); module.exports = cancelRequest; diff --git a/src/routes/index.js b/src/routes/index.js index b380474..dfa75a0 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -2,7 +2,7 @@ const Router = require("koa-router"); const posts = require("./posts"); const banners = require("./banners"); -const bulletins = require("./bulletins"); +const boards = require("./boards"); const admins = require("./admins"); const auth = require("./auth"); const payments = require("./payments"); @@ -18,7 +18,7 @@ router.use("/auth", auth.routes()); router.use("/posts", posts.routes()); router.use("/admins", admins.routes()); router.use("/banners", banners.routes()); -router.use("/bulletins", bulletins.routes()); +router.use("/boards", boards.routes()); router.use("/payments", payments.routes()); router.use("/cancelRequest", cancelRequest.routes()); diff --git a/src/routes/payments/payments.ctrl.js b/src/routes/payments/payments.ctrl.js index 4ed279e..e19ff29 100644 --- a/src/routes/payments/payments.ctrl.js +++ b/src/routes/payments/payments.ctrl.js @@ -2,35 +2,35 @@ const models = require("../../database/models"); const Op = require("sequelize").Op; exports.write = async (ctx) => { - const { ku_std_no_list, year, semester } = ctx.request.body; + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const admin = await models.Admin.findOne({ + where: { id }, + }); + ctx.assert(admin, 401); + const { studentNumberList, year, semester } = ctx.request.body; const bulkData = []; - ku_std_no_list.map((id) => { + studentNumberList.map((id) => { bulkData.push({ - ku_std_no: id, + studentNumber: id, year, semester, }); }); - const res = await models.payment.bulkCreate(bulkData); + const res = await models.Payment.bulkCreate(bulkData); if (res) { ctx.response.body = bulkData.length; } }; exports.list = async (ctx) => { - if (ctx.request.user) { - const { id } = ctx.request.user; - const user = await models.user.findOne({ where: { id } }); - console.log(user.ku_std_no); - const res = await models.payment.findAll({ - where: { ku_std_no: user.ku_std_no }, - }); - if (res) { - ctx.body = { payments: res }; - } else { - ctx.body = { payments: [] }; - } - } else { - ctx.body = { payments: [] }; - } + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const student = await models.Student.findOne({ + where: { id }, + include: models.Payment, + }); + ctx.assert(student, 401); + console.log(student); + ctx.body = { payments: student.Payments }; }; diff --git a/src/routes/posts/posts.ctrl.js b/src/routes/posts/posts.ctrl.js index 253438a..4fa2288 100644 --- a/src/routes/posts/posts.ctrl.js +++ b/src/routes/posts/posts.ctrl.js @@ -1,5 +1,5 @@ -const models = require('../../database/models'); -const Op = require('sequelize').Op; +const models = require("../../database/models"); +const Op = require("sequelize").Op; /** @swagger * /posts: @@ -60,6 +60,12 @@ const Op = require('sequelize').Op; * description: Internal Server Error */ exports.write = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const admin = await models.Admin.findOne({ + where: { id }, + }); + ctx.assert(admin, 401); const { title, author, content, bulletinId } = ctx.request.body; const post = { title: title, @@ -67,11 +73,9 @@ exports.write = async (ctx) => { content: content, bulletin_id: parseInt(bulletinId), }; - console.log(post); - await models.post - .create(post) + await models.Post.create(post) .then((res) => { - console.log('포스트 업로드 성공!'); + console.log("포스트 업로드 성공!"); ctx.body = res; }) .catch((err) => { @@ -174,13 +178,12 @@ exports.list = async (ctx) => { var body = {}; - await models.post - .findAll({ - order: [['created_at', 'DESC']], - offset: offset, - limit: POST_NUM_PER_PAGE, - where: where, - }) + await models.Post.findAll({ + order: [["created_at", "DESC"]], + offset: offset, + limit: POST_NUM_PER_PAGE, + where: where, + }) .then((res) => { if (!res) body.posts = res; body.posts = res; @@ -189,10 +192,9 @@ exports.list = async (ctx) => { console.log(err); }); - await models.post - .count({ - where: where, - }) + await models.Post.count({ + where: where, + }) .then((res) => { body.lastPage = Math.ceil(res / POST_NUM_PER_PAGE); }) @@ -259,14 +261,13 @@ exports.list = async (ctx) => { exports.read = async (ctx) => { const { id } = ctx.params; - await models.post - .findOne({ - where: { id }, - }) + await models.Post.findOne({ + where: { id }, + }) .then((res) => { ctx.body = res; - models.post.update({ views: res.views + 1 }, { where: { id } }); + models.Post.update({ views: res.views + 1 }, { where: { id } }); }) .catch((err) => { console.log(err); @@ -305,20 +306,25 @@ exports.read = async (ctx) => { * description: Internal Server Error */ exports.remove = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const adminId = ctx.request.user.id; + const admin = await models.Admin.findOne({ + where: { id: adminId }, + }); + ctx.assert(admin, 401); const { id } = ctx.params; - await models.post - .destroy({ - where: { id: id }, - }) + await models.Post.destroy({ + where: { id: id }, + }) .then((res) => { if (!res) { ctx.status = 404; ctx.body = { - message: '포스트가 존재하지 않습니다.', + message: "포스트가 존재하지 않습니다.", }; } else { - console.log('포스트 삭제 성공!'); + console.log("포스트 삭제 성공!"); ctx.status = 204; } }) @@ -378,6 +384,12 @@ exports.remove = async (ctx) => { * description: Internal Server Error */ exports.update = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const adminId = ctx.request.user.id; + const admin = await models.Admin.findOne({ + where: { id: adminId }, + }); + ctx.assert(admin, 401); const { id } = ctx.params; const { title, author, content, views } = ctx.request.body; const post = { @@ -387,13 +399,12 @@ exports.update = async (ctx) => { views: views, }; - await models.post - .update(post, { - where: { id: id }, - }) + await models.Post.update(post, { + where: { id: id }, + }) .then((res) => { ctx.body = post; - console.log('포스트 업데이트 성공!'); + console.log("포스트 업데이트 성공!"); }) .catch((err) => { console.log(err); diff --git a/src/utils/index.js b/src/utils/index.js index ff8ee61..ed771b2 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -25,7 +25,7 @@ function decodeToken(token) { } async function jwtMiddleware(ctx, next) { - const token = ctx.cookies.get("kaistua_web_access_token"); + const token = ctx.cookies.get(process.env.ACCESS_TOKEN); if (!token) return next(); // 토큰이 없으면 바로 다음 작업을 진행합니다. try { const decoded = await decodeToken(token.toString()); // 토큰을 디코딩 합니다 @@ -35,7 +35,7 @@ async function jwtMiddleware(ctx, next) { const { id } = decoded; const { generateToken } = require("../routes/auth/generateToken"); const freshToken = await generateToken({ id }); - ctx.cookies.set("kaistua_web_access_token", freshToken, { + ctx.cookies.set(process.env.ACCESS_TOKEN, freshToken, { maxAge: 1000 * 60 * 60 * 24 * 7, // 7days httpOnly: true, }); From c39afe4e390d3b5da01e605693101c7f9e8e19c6 Mon Sep 17 00:00:00 2001 From: winningarc Date: Fri, 28 Aug 2020 22:36:21 +0900 Subject: [PATCH 16/26] fix: payment api --- .../cancelRequest/cancelRequest.ctrl.js | 44 ++++++++++++------- src/routes/payments/index.js | 3 +- src/routes/payments/payments.ctrl.js | 3 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/routes/cancelRequest/cancelRequest.ctrl.js b/src/routes/cancelRequest/cancelRequest.ctrl.js index a5c9920..2d268c2 100644 --- a/src/routes/cancelRequest/cancelRequest.ctrl.js +++ b/src/routes/cancelRequest/cancelRequest.ctrl.js @@ -13,15 +13,26 @@ exports.post = async (ctx) => { }); ctx.assert(student, 401); const { year, semester } = ctx.request.body; - const { studentNumber, korName, engName } = student; - const res = await models.CancelRequest.create({ - studentNumber, - korName, - engName, - year, - semester, + const { studentNumber } = student; + const res = await models.CancelRequest.findOne({ + where: { + studentNumber, + year, + semester, + }, }); - ctx.assert(res, 400); + if (res) { + ctx.status = 200; + ctx.body = res; + } else { + const newRequest = await models.CancelRequest.create({ + studentNumber, + year, + semester, + }); + ctx.assert(newRequest, 400); + ctx.status = 204; + } }; /** @@ -52,13 +63,10 @@ exports.getOne = async (ctx) => { where: { id }, include: models.CancelRequest, }); - ctx.assert(student, 401); + ctx.assert(student.CancelRequest, 404); - if (student.CancelRequest) { - ctx.body = { exists: true }; - } else { - ctx.body = { exists: true }; - } + ctx.status = 200; + ctx.body = student.CancelRequest; }; /** @@ -68,11 +76,15 @@ exports.getOne = async (ctx) => { exports.delete = async (ctx) => { ctx.assert(ctx.request.user, 401); const { id } = ctx.request.user; - const { year, semester } = ctx.request.params; + const { year, semester } = ctx.query; + ctx.assert(year && semester, 400); const student = await models.Student.findOne({ where: { id }, include: { model: models.CancelRequest, where: { year, semester } }, }); - ctx.assert(student, 401); + if (!student) { + ctx.status = 204; + return; + } ctx.body = student.CancelRequests[0].destroy(); }; diff --git a/src/routes/payments/index.js b/src/routes/payments/index.js index 30e00da..e38a611 100644 --- a/src/routes/payments/index.js +++ b/src/routes/payments/index.js @@ -2,8 +2,7 @@ const Router = require("koa-router"); const payments = new Router(); const paymentsCtrl = require("./payments.ctrl"); -payments.post("/", paymentsCtrl.write); +payments.post("/admin", paymentsCtrl.bulkUpload); payments.get("/", paymentsCtrl.list); -// payments.get("/:id", paymentsCtrl.read); module.exports = payments; diff --git a/src/routes/payments/payments.ctrl.js b/src/routes/payments/payments.ctrl.js index e19ff29..573576d 100644 --- a/src/routes/payments/payments.ctrl.js +++ b/src/routes/payments/payments.ctrl.js @@ -1,7 +1,7 @@ const models = require("../../database/models"); const Op = require("sequelize").Op; -exports.write = async (ctx) => { +exports.bulkUpload = async (ctx) => { ctx.assert(ctx.request.user, 401); const { id } = ctx.request.user; const admin = await models.Admin.findOne({ @@ -31,6 +31,5 @@ exports.list = async (ctx) => { include: models.Payment, }); ctx.assert(student, 401); - console.log(student); ctx.body = { payments: student.Payments }; }; From 31cc697dd5e74103e6269e728c128795a9ca2e53 Mon Sep 17 00:00:00 2001 From: winningarc Date: Fri, 28 Aug 2020 22:36:29 +0900 Subject: [PATCH 17/26] feature: seeders --- .../seeders/20200407115009-bannerData.js | 22 -------- .../seeders/20200412080854-postData.js | 56 ------------------- .../seeders/20200419080205-bulletinData.js | 30 ---------- .../seeders/20200419080205-create-boards.js | 30 ++++++++++ 4 files changed, 30 insertions(+), 108 deletions(-) delete mode 100644 src/database/seeders/20200407115009-bannerData.js delete mode 100644 src/database/seeders/20200412080854-postData.js delete mode 100644 src/database/seeders/20200419080205-bulletinData.js create mode 100644 src/database/seeders/20200419080205-create-boards.js diff --git a/src/database/seeders/20200407115009-bannerData.js b/src/database/seeders/20200407115009-bannerData.js deleted file mode 100644 index 10bd14e..0000000 --- a/src/database/seeders/20200407115009-bannerData.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.bulkInsert( - 'banner', - [ - { - id: 1, - url: 'http://bitly.kr/TDZyC8p2', - createdAt: new Date(), - updatedAt: new Date(), - }, - ], - {}, - ); - }, - - down: (queryInterface, Sequelize) => { - return queryInterface.bulkDelete('banner', null, {}); - }, -}; diff --git a/src/database/seeders/20200412080854-postData.js b/src/database/seeders/20200412080854-postData.js deleted file mode 100644 index 767f00f..0000000 --- a/src/database/seeders/20200412080854-postData.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; - -module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.bulkInsert( - 'post', - [ - { - id: 1, - title: 'asdf', - author: '복지국', - content: '욱카 이용권은 월 3000원에 판매되고 있습니다.', - views: 483, - bulletinId: 1, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - id: 2, - title: '[제휴] <욱카>, 학기당 50022회 사용 가능', - author: '복지국2', - content: '욱카 이용권은 월 3000원에 판매되고 있습니다.', - views: 483, - bulletinId: 1, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - id: 3, - title: '[제휴] <욱카>, 학기당 500423회 사용 가능', - author: '복지국3', - content: '욱카 이용권은 월 3000원에 판매되고 있습니다.', - views: 483, - bulletinId: 1, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - id: 4, - title: '[제휴] <욱카>, 학기당 50032회 사용 가능', - author: '복지국4', - content: '욱카 이용권은 월 3000원에 판매되고 있습니다.', - views: 483, - bulletinId: 1, - createdAt: new Date(), - updatedAt: new Date(), - }, - ], - {}, - ); - }, - - down: (queryInterface, Sequelize) => { - return queryInterface.bulkDelete('post', null, {}); - }, -}; diff --git a/src/database/seeders/20200419080205-bulletinData.js b/src/database/seeders/20200419080205-bulletinData.js deleted file mode 100644 index b9d11c7..0000000 --- a/src/database/seeders/20200419080205-bulletinData.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.bulkInsert( - 'bulletin', - [ - { - id: 1, - title: '공지사항', - description: '공지사항 게시판 입니다~!', - createdAt: new Date(), - updatedAt: new Date(), - }, - { - id: 2, - title: '학생복지', - description: '학생복지/제휴 게시판 입니다~!', - createdAt: new Date(), - updatedAt: new Date(), - }, - ], - {}, - ); - }, - - down: (queryInterface, Sequelize) => { - return queryInterface.bulkDelete('bulletin', null, {}); - }, -}; diff --git a/src/database/seeders/20200419080205-create-boards.js b/src/database/seeders/20200419080205-create-boards.js new file mode 100644 index 0000000..0e1e7fc --- /dev/null +++ b/src/database/seeders/20200419080205-create-boards.js @@ -0,0 +1,30 @@ +"use strict"; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.bulkInsert( + "Board", + [ + { + id: 1, + korTitle: "공지사항", + engTitle: "Announcements", + korDescription: "", + engDescription: "", + }, + { + id: 2, + korTitle: "학생 복지", + engTitle: "Student Welfare", + korDescription: "학우들을 위한 제휴 및 기타 복지사업", + engDescription: "Partnerships and discounts for students", + }, + ], + {} + ); + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.bulkDelete("Board", null, {}); + }, +}; From cc6f7300e3afcf2cc05dc739be97b19ad24cc6f2 Mon Sep 17 00:00:00 2001 From: winningarc Date: Sun, 30 Aug 2020 05:10:28 +0900 Subject: [PATCH 18/26] fix: foreignKey definitions and reimplement apis --- .../migrations/20200827224019-create-post.js | 2 +- .../20200827230222-create-associations.js | 4 +- src/database/models/CancelRequest.js | 2 +- src/database/models/Student.js | 2 +- src/database/models/payment.js | 2 +- src/database/models/post.js | 9 ++- src/routes/admins/admins.ctrl.js | 10 ++- src/routes/auth/auth.ctrl.js | 22 ++++-- src/routes/boards/boards.ctrl.js | 2 +- .../cancelRequest/cancelRequest.ctrl.js | 4 +- src/routes/payments/payments.ctrl.js | 24 +++++-- src/routes/posts/posts.ctrl.js | 67 ++++++++----------- 12 files changed, 83 insertions(+), 67 deletions(-) diff --git a/src/database/migrations/20200827224019-create-post.js b/src/database/migrations/20200827224019-create-post.js index d71564d..8cccb0a 100644 --- a/src/database/migrations/20200827224019-create-post.js +++ b/src/database/migrations/20200827224019-create-post.js @@ -12,7 +12,7 @@ module.exports = { korTitle: Sequelize.TEXT, engTitle: Sequelize.TEXT, korContent: Sequelize.TEXT, - korContent: Sequelize.TEXT, + engContent: Sequelize.TEXT, views: { type: Sequelize.INTEGER, defaultValue: 0, diff --git a/src/database/migrations/20200827230222-create-associations.js b/src/database/migrations/20200827230222-create-associations.js index b5af2fb..2101a4b 100644 --- a/src/database/migrations/20200827230222-create-associations.js +++ b/src/database/migrations/20200827230222-create-associations.js @@ -6,7 +6,7 @@ module.exports = { return queryInterface .addColumn( "Post", // name of Source model - "BoardId", // name of the key we're adding + "boardId", // name of the key we're adding { type: Sequelize.INTEGER, references: { @@ -56,7 +56,7 @@ module.exports = { return queryInterface .removeColumn( "Post", // name of Source model - "BoardId" // key we want to remove + "boardId" // key we want to remove ) .then(() => { // remove Student hasMany CancelRequest diff --git a/src/database/models/CancelRequest.js b/src/database/models/CancelRequest.js index 59361eb..c835328 100644 --- a/src/database/models/CancelRequest.js +++ b/src/database/models/CancelRequest.js @@ -19,7 +19,7 @@ module.exports = (sequelize, DataTypes) => { ); CancelRequest.associate = function (models) { // associations can be defined here - models.CancelRequest.belongsTo(models.Student, { + CancelRequest.belongsTo(models.Student, { targetKey: "studentNumber", foreignKey: "studentNumber", }); diff --git a/src/database/models/Student.js b/src/database/models/Student.js index 94a6a8b..41bcaac 100644 --- a/src/database/models/Student.js +++ b/src/database/models/Student.js @@ -23,8 +23,8 @@ module.exports = (sequelize, DataTypes) => { Student.associate = function (models) { // associations can be defined here Student.hasMany(models.CancelRequest, { - targetKey: "studentNumber", foreignKey: "studentNumber", + sourceKey: "studentNumber", }); Student.hasMany(models.Payment); }; diff --git a/src/database/models/payment.js b/src/database/models/payment.js index 0eb32e8..aba6619 100644 --- a/src/database/models/payment.js +++ b/src/database/models/payment.js @@ -21,7 +21,7 @@ module.exports = (sequelize, DataTypes) => { ); Payment.associate = function (models) { // associations can be defined here - models.Payment.belongsTo(models.Student); + models.Payment.belongsTo(models.Student, { foreignKey: "studentId" }); }; return Payment; }; diff --git a/src/database/models/post.js b/src/database/models/post.js index c52399a..ca3a617 100644 --- a/src/database/models/post.js +++ b/src/database/models/post.js @@ -12,16 +12,16 @@ module.exports = (sequelize, DataTypes) => { korTitle: DataTypes.TEXT, engTitle: DataTypes.TEXT, korContent: DataTypes.TEXT, - korContent: DataTypes.TEXT, + engContent: DataTypes.TEXT, views: { type: DataTypes.INTEGER, defaultValue: 0, }, isActive: DataTypes.BOOLEAN, isNew: { - type: DataTypes.BOOLEAN, + type: DataTypes.VIRTUAL, get: function () { - const createdAt = this.getDataValue("createdAt"); + const createdAt = this.createdAt; const createdAtDate = new Date(createdAt); const now = new Date(); return createdAtDate.getMinutes() > now.getMinutes() - 60 * 24; @@ -30,14 +30,13 @@ module.exports = (sequelize, DataTypes) => { }, { freezeTableName: true, - paranoid: true, charset: "utf8", collate: "utf8_general_ci", } ); Post.associate = function (models) { - models.Post.belongsTo(models.Board); + models.Post.belongsTo(models.Board, { foreignKey: "boardId" }); }; return Post; diff --git a/src/routes/admins/admins.ctrl.js b/src/routes/admins/admins.ctrl.js index 7ad66bb..e4269a7 100644 --- a/src/routes/admins/admins.ctrl.js +++ b/src/routes/admins/admins.ctrl.js @@ -130,10 +130,16 @@ exports.login = async (ctx) => { * description: Internal Server Error */ exports.check = async (ctx) => { - ctx.assert(ctx.request.user, 401); + if (!ctx.request.user) { + ctx.status = 204; + return; + } const { id } = ctx.request.user; const admin = await models.Admin.findOne({ where: { id } }); - ctx.assert(admin, 401, "Test"); + if (!admin) { + ctx.status = 204; + return; + } ctx.status = 200; ctx.body = { auth: "admin" }; }; diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index bee69a5..0da3d4b 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -45,12 +45,22 @@ exports.logout = async (ctx) => { }; exports.check = async (ctx) => { - ctx.assert(ctx.request.user, 401); + if (!ctx.request.user) { + ctx.status = 204; + return; + } const { id } = ctx.request.user; const student = await models.Student.findOne({ where: { id } }); - ctx.assert(student, 401); - ctx.body = { - auth: "student", - name: student.korName || student.engName, - }; + if (!student) { + const admin = await models.Admin.findOne({ where: { id } }); + if (!admin) { + ctx.status = 204; + return; + } else { + ctx.body = { auth: "admin" }; + return; + } + } + ctx.status = 200; + ctx.body = { auth: "student", name: student.korName || student.engName }; }; diff --git a/src/routes/boards/boards.ctrl.js b/src/routes/boards/boards.ctrl.js index cdd2d03..a18c699 100644 --- a/src/routes/boards/boards.ctrl.js +++ b/src/routes/boards/boards.ctrl.js @@ -105,7 +105,7 @@ exports.create = async (ctx) => { * description: Internal Server Error */ exports.list = async (ctx) => { - const res = models.Board.findAll(); + const res = await models.Board.findAll(); ctx.assert(res, 404); ctx.body = res; }; diff --git a/src/routes/cancelRequest/cancelRequest.ctrl.js b/src/routes/cancelRequest/cancelRequest.ctrl.js index 2d268c2..9d94b70 100644 --- a/src/routes/cancelRequest/cancelRequest.ctrl.js +++ b/src/routes/cancelRequest/cancelRequest.ctrl.js @@ -63,10 +63,10 @@ exports.getOne = async (ctx) => { where: { id }, include: models.CancelRequest, }); - ctx.assert(student.CancelRequest, 404); + ctx.assert(student.CancelRequests, 400); ctx.status = 200; - ctx.body = student.CancelRequest; + ctx.body = student.CancelRequests; }; /** diff --git a/src/routes/payments/payments.ctrl.js b/src/routes/payments/payments.ctrl.js index 573576d..7cbb585 100644 --- a/src/routes/payments/payments.ctrl.js +++ b/src/routes/payments/payments.ctrl.js @@ -10,13 +10,23 @@ exports.bulkUpload = async (ctx) => { ctx.assert(admin, 401); const { studentNumberList, year, semester } = ctx.request.body; const bulkData = []; - studentNumberList.map((id) => { - bulkData.push({ - studentNumber: id, - year, - semester, - }); - }); + await Promise.all( + studentNumberList.map(async (studentNumber) => { + const payment = { + studentNumber, + year, + semester, + }; + const student = await models.Student.findOne({ + where: { studentNumber }, + }); + if (student) { + payment.studentId = student.id; + console.log(payment); + } + bulkData.push(payment); + }) + ); const res = await models.Payment.bulkCreate(bulkData); if (res) { ctx.response.body = bulkData.length; diff --git a/src/routes/posts/posts.ctrl.js b/src/routes/posts/posts.ctrl.js index 4fa2288..58131d8 100644 --- a/src/routes/posts/posts.ctrl.js +++ b/src/routes/posts/posts.ctrl.js @@ -66,21 +66,25 @@ exports.write = async (ctx) => { where: { id }, }); ctx.assert(admin, 401); - const { title, author, content, bulletinId } = ctx.request.body; + const { + author, + korTitle, + engTitle, + korContent, + engContent, + bulletinId, + } = ctx.request.body; const post = { - title: title, - author: author, - content: content, - bulletin_id: parseInt(bulletinId), + author, + korTitle, + engTitle, + korContent, + engContent, + bulletinId: parseInt(bulletinId), }; - await models.Post.create(post) - .then((res) => { - console.log("포스트 업로드 성공!"); - ctx.body = res; - }) - .catch((err) => { - console.log(err); - }); + const res = await models.Post.create(post); + ctx.assert(res, 400); + ctx.status = 204; }; /** @swagger @@ -158,17 +162,14 @@ exports.write = async (ctx) => { * description: Internal Server Error */ exports.list = async (ctx) => { - const { page, title, author, bulletinId } = ctx.request.query; + const { page, title, author, boardId } = ctx.request.query; const POST_NUM_PER_PAGE = 15; - if (page < 1) { - ctx.status = 400; - return; - } + ctx.assert(page > 0, 400); const offset = POST_NUM_PER_PAGE * (page - 1); - var where = { bulletin_id: parseInt(bulletinId) }; + var where = { boardId: parseInt(boardId) }; if (author) where.author = author; if (title) @@ -176,31 +177,21 @@ exports.list = async (ctx) => { [Op.like]: `%${title}%`, }; - var body = {}; + const body = {}; // Response body - await models.Post.findAll({ - order: [["created_at", "DESC"]], + const posts = await models.Post.findAll({ + order: [["createdAt", "DESC"]], offset: offset, limit: POST_NUM_PER_PAGE, where: where, - }) - .then((res) => { - if (!res) body.posts = res; - body.posts = res; - }) - .catch((err) => { - console.log(err); - }); + }); + + body.posts = posts; - await models.Post.count({ + const postCount = await models.Post.count({ where: where, - }) - .then((res) => { - body.lastPage = Math.ceil(res / POST_NUM_PER_PAGE); - }) - .catch((err) => { - console.log(err); - }); + }); + body.lastPage = Math.ceil(postCount / POST_NUM_PER_PAGE); ctx.body = body; }; From 64494f7ef64fca4300e86ac84f77852e7b90d567 Mon Sep 17 00:00:00 2001 From: winningarc Date: Mon, 31 Aug 2020 22:57:26 +0900 Subject: [PATCH 19/26] fix: apis --- src/database/models/Board.js | 2 +- src/database/models/Student.js | 4 +++- src/database/models/post.js | 3 ++- src/routes/auth/auth.ctrl.js | 6 +++++- src/routes/banners/banners.ctrl.js | 2 ++ src/routes/posts/posts.ctrl.js | 22 ++++++++++++++-------- 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/database/models/Board.js b/src/database/models/Board.js index d0fb462..cce9ffd 100644 --- a/src/database/models/Board.js +++ b/src/database/models/Board.js @@ -22,7 +22,7 @@ module.exports = (sequelize, DataTypes) => { ); Board.associate = function (models) { - models.Board.hasMany(models.Post); + models.Board.hasMany(models.Post, { foreignKey: "boardId" }); }; return Board; diff --git a/src/database/models/Student.js b/src/database/models/Student.js index 41bcaac..8c42854 100644 --- a/src/database/models/Student.js +++ b/src/database/models/Student.js @@ -26,7 +26,9 @@ module.exports = (sequelize, DataTypes) => { foreignKey: "studentNumber", sourceKey: "studentNumber", }); - Student.hasMany(models.Payment); + Student.hasMany(models.Payment, { + foreignKey: "studentId", + }); }; return Student; }; diff --git a/src/database/models/post.js b/src/database/models/post.js index ca3a617..0534fb1 100644 --- a/src/database/models/post.js +++ b/src/database/models/post.js @@ -20,10 +20,11 @@ module.exports = (sequelize, DataTypes) => { isActive: DataTypes.BOOLEAN, isNew: { type: DataTypes.VIRTUAL, - get: function () { + get() { const createdAt = this.createdAt; const createdAtDate = new Date(createdAt); const now = new Date(); + console.log(now); return createdAtDate.getMinutes() > now.getMinutes() - 60 * 24; }, }, diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index 0da3d4b..618e77f 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -62,5 +62,9 @@ exports.check = async (ctx) => { } } ctx.status = 200; - ctx.body = { auth: "student", name: student.korName || student.engName }; + ctx.body = { + auth: "student", + korName: student.korName, + engName: student.engName, + }; }; diff --git a/src/routes/banners/banners.ctrl.js b/src/routes/banners/banners.ctrl.js index 70edecf..bc2aa60 100644 --- a/src/routes/banners/banners.ctrl.js +++ b/src/routes/banners/banners.ctrl.js @@ -51,6 +51,8 @@ exports.upload = async (ctx) => { const { image, link, isActive } = ctx.request.body; const res = await models.Banner.create({ image, link, isActive }); ctx.assert(res, 400); + ctx.status = 200; + ctx.body = res; }; /** @swagger diff --git a/src/routes/posts/posts.ctrl.js b/src/routes/posts/posts.ctrl.js index 58131d8..60ccf79 100644 --- a/src/routes/posts/posts.ctrl.js +++ b/src/routes/posts/posts.ctrl.js @@ -60,19 +60,20 @@ const Op = require("sequelize").Op; * description: Internal Server Error */ exports.write = async (ctx) => { - ctx.assert(ctx.request.user, 401); - const { id } = ctx.request.user; - const admin = await models.Admin.findOne({ - where: { id }, - }); - ctx.assert(admin, 401); + // ctx.assert(ctx.request.user, 401); + // const { id } = ctx.request.user; + // const admin = await models.Admin.findOne({ + // where: { id }, + // }); + // ctx.assert(Cadmin, 401); const { author, korTitle, engTitle, korContent, engContent, - bulletinId, + isActive, + boardId, } = ctx.request.body; const post = { author, @@ -80,7 +81,8 @@ exports.write = async (ctx) => { engTitle, korContent, engContent, - bulletinId: parseInt(bulletinId), + isActive, + boardId: parseInt(boardId), }; const res = await models.Post.create(post); ctx.assert(res, 400); @@ -184,6 +186,7 @@ exports.list = async (ctx) => { offset: offset, limit: POST_NUM_PER_PAGE, where: where, + raw: false, }); body.posts = posts; @@ -254,9 +257,12 @@ exports.read = async (ctx) => { await models.Post.findOne({ where: { id }, + raw: false, + include: models.Board, }) .then((res) => { ctx.body = res; + console.log(res); models.Post.update({ views: res.views + 1 }, { where: { id } }); }) From 4a2d0f927969695ec450d483459c3fb8ee4a2090 Mon Sep 17 00:00:00 2001 From: winningarc Date: Mon, 31 Aug 2020 23:17:16 +0900 Subject: [PATCH 20/26] fix: migration --- src/database/migrations/20200827224111-create-student.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/database/migrations/20200827224111-create-student.js b/src/database/migrations/20200827224111-create-student.js index 506634e..162965d 100644 --- a/src/database/migrations/20200827224111-create-student.js +++ b/src/database/migrations/20200827224111-create-student.js @@ -8,7 +8,11 @@ module.exports = { defaultValue: Sequelize.UUIDV4, primaryKey: true, }, - studentNumber: { type: Sequelize.INTEGER, unique: true }, + studentNumber: { + type: Sequelize.INTEGER, + allowNull: false, + unique: true, + }, kaistUid: Sequelize.STRING, korName: Sequelize.STRING, engName: Sequelize.STRING, From 992e1464830a693dc383416f2f8c5cfd36608d05 Mon Sep 17 00:00:00 2001 From: winningarc Date: Fri, 18 Sep 2020 22:07:12 +0900 Subject: [PATCH 21/26] feat: add redirect link --- src/routes/auth/auth.ctrl.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/routes/auth/auth.ctrl.js b/src/routes/auth/auth.ctrl.js index 618e77f..385e3b9 100644 --- a/src/routes/auth/auth.ctrl.js +++ b/src/routes/auth/auth.ctrl.js @@ -11,8 +11,9 @@ exports.signup = async (ctx) => { engName: USER_INFO.displayname, affiliation: USER_INFO.ku_acad_name, }; + const { key, redirect } = JSON.parse(state); var record = await models.Student.findOne({ where: newStudent }); - if (record || state === process.env.REGISTER_KEY) { + if (record || key === process.env.REGISTER_KEY) { if (!record) { record = await models.Student.create(newStudent); const studentId = record.id; @@ -33,7 +34,8 @@ exports.signup = async (ctx) => { maxAge: 1000 * 60 * 60 * 24 * 7, overwrite: true, }); - ctx.redirect(`${process.env.WEB_FRONTEND}/web/main`); + if (redirect) ctx.redirect(redirect); + else ctx.redirect(`${process.env.WEB_FRONTEND}/web/main`); } else { ctx.redirect(`${process.env.WEB_FRONTEND}/web/auth/agreement/login`); } From 8121c7a098df0bfdfa5372bb419b1420c6d93874 Mon Sep 17 00:00:00 2001 From: winningarc Date: Thu, 1 Oct 2020 00:22:08 +0900 Subject: [PATCH 22/26] feat: add english author to Post --- .../migrations/20200926153605-edit-post.js | 25 ++++++++++ src/database/models/post.js | 4 +- src/routes/posts/posts.ctrl.js | 49 +++++-------------- 3 files changed, 39 insertions(+), 39 deletions(-) create mode 100644 src/database/migrations/20200926153605-edit-post.js diff --git a/src/database/migrations/20200926153605-edit-post.js b/src/database/migrations/20200926153605-edit-post.js new file mode 100644 index 0000000..134ea68 --- /dev/null +++ b/src/database/migrations/20200926153605-edit-post.js @@ -0,0 +1,25 @@ +"use strict"; + +module.exports = { + up: (queryInterface, Sequelize) => { + return Promise.all([ + queryInterface.addColumn("Post", "korAuthor", { + type: Sequelize.TEXT, + }), + queryInterface.addColumn("Post", "engAuthor", { + type: Sequelize.TEXT, + }), + queryInterface.removeColumn("Post", "author"), + ]); + }, + + down: (queryInterface, Sequelize) => { + return Promise.all([ + queryInterface.removeColumn("Post", "korAuthor"), + queryInterface.removeColumn("Post", "engAuthor"), + queryInterface.addColumn("Post", "author", { + type: Sequelize.TEXT, + }), + ]); + }, +}; diff --git a/src/database/models/post.js b/src/database/models/post.js index 0534fb1..a2f68e0 100644 --- a/src/database/models/post.js +++ b/src/database/models/post.js @@ -8,7 +8,8 @@ module.exports = (sequelize, DataTypes) => { defaultValue: DataTypes.UUIDV4, primaryKey: true, }, - author: DataTypes.TEXT, + korAuthor: DataTypes.TEXT, + engAuthor: DataTypes.TEXT, korTitle: DataTypes.TEXT, engTitle: DataTypes.TEXT, korContent: DataTypes.TEXT, @@ -24,7 +25,6 @@ module.exports = (sequelize, DataTypes) => { const createdAt = this.createdAt; const createdAtDate = new Date(createdAt); const now = new Date(); - console.log(now); return createdAtDate.getMinutes() > now.getMinutes() - 60 * 24; }, }, diff --git a/src/routes/posts/posts.ctrl.js b/src/routes/posts/posts.ctrl.js index 60ccf79..2222b75 100644 --- a/src/routes/posts/posts.ctrl.js +++ b/src/routes/posts/posts.ctrl.js @@ -60,30 +60,14 @@ const Op = require("sequelize").Op; * description: Internal Server Error */ exports.write = async (ctx) => { - // ctx.assert(ctx.request.user, 401); - // const { id } = ctx.request.user; - // const admin = await models.Admin.findOne({ - // where: { id }, - // }); - // ctx.assert(Cadmin, 401); - const { - author, - korTitle, - engTitle, - korContent, - engContent, - isActive, - boardId, - } = ctx.request.body; - const post = { - author, - korTitle, - engTitle, - korContent, - engContent, - isActive, - boardId: parseInt(boardId), - }; + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const admin = await models.Admin.findOne({ + where: { id }, + }); + ctx.assert(admin, 401); + const post = ctx.request.body; + post.boardId = parseInt(post.boardId); const res = await models.Post.create(post); ctx.assert(res, 400); ctx.status = 204; @@ -164,7 +148,7 @@ exports.write = async (ctx) => { * description: Internal Server Error */ exports.list = async (ctx) => { - const { page, title, author, boardId } = ctx.request.query; + const { page, boardId } = ctx.request.query; const POST_NUM_PER_PAGE = 15; ctx.assert(page > 0, 400); @@ -173,14 +157,6 @@ exports.list = async (ctx) => { var where = { boardId: parseInt(boardId) }; - if (author) where.author = author; - if (title) - where.title = { - [Op.like]: `%${title}%`, - }; - - const body = {}; // Response body - const posts = await models.Post.findAll({ order: [["createdAt", "DESC"]], offset: offset, @@ -189,14 +165,13 @@ exports.list = async (ctx) => { raw: false, }); - body.posts = posts; - const postCount = await models.Post.count({ where: where, }); - body.lastPage = Math.ceil(postCount / POST_NUM_PER_PAGE); - ctx.body = body; + const lastPage = Math.ceil(postCount / POST_NUM_PER_PAGE); + + ctx.body = { posts, lastPage }; }; /** @swagger From 64a535d1322f425ad051ec8d6981f6f4334cb303 Mon Sep 17 00:00:00 2001 From: winningarc Date: Fri, 2 Oct 2020 07:17:00 +0900 Subject: [PATCH 23/26] feat: add petition table --- .../20200930185340-create-petition.js | 23 ++++++ .../20201001091755-create-associations.js | 33 +++++++++ src/database/models/Petition.js | 42 +++++++++++ src/database/models/Student.js | 1 + src/database/models/payment.js | 2 +- src/database/models/post.js | 5 +- src/routes/index.js | 2 + src/routes/petitions/index.js | 10 +++ src/routes/petitions/petitions.ctrl.js | 74 +++++++++++++++++++ 9 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 src/database/migrations/20200930185340-create-petition.js create mode 100644 src/database/migrations/20201001091755-create-associations.js create mode 100644 src/database/models/Petition.js create mode 100644 src/routes/petitions/index.js create mode 100644 src/routes/petitions/petitions.ctrl.js diff --git a/src/database/migrations/20200930185340-create-petition.js b/src/database/migrations/20200930185340-create-petition.js new file mode 100644 index 0000000..4768078 --- /dev/null +++ b/src/database/migrations/20200930185340-create-petition.js @@ -0,0 +1,23 @@ +"use strict"; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.createTable("Petition", { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + korTitle: Sequelize.TEXT, + engTitle: Sequelize.TEXT, + korContent: Sequelize.TEXT, + engContent: Sequelize.TEXT, + createdAt: Sequelize.DATE, + updatedAt: Sequelize.DATE, + }); + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.dropTable("Petition"); + }, +}; diff --git a/src/database/migrations/20201001091755-create-associations.js b/src/database/migrations/20201001091755-create-associations.js new file mode 100644 index 0000000..5cbd2d2 --- /dev/null +++ b/src/database/migrations/20201001091755-create-associations.js @@ -0,0 +1,33 @@ +"use strict"; + +module.exports = { + up: async (queryInterface, Sequelize) => { + // Board hasMany Post + return queryInterface.createTable("Student_Petition", { + StudentId: { + type: Sequelize.UUID, + references: { + model: "Student", // name of Target model + key: "id", // key in Target model that we're referencing + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + }, + PetitionId: { + type: Sequelize.UUID, + references: { + model: "Petition", // name of Target model + key: "id", // key in Target model that we're referencing + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + }, + createdAt: Sequelize.DATE, + updatedAt: Sequelize.DATE, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Student_Petition"); + }, +}; diff --git a/src/database/models/Petition.js b/src/database/models/Petition.js new file mode 100644 index 0000000..ad46544 --- /dev/null +++ b/src/database/models/Petition.js @@ -0,0 +1,42 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + const Petition = sequelize.define( + "Petition", + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + korTitle: DataTypes.TEXT, + engTitle: DataTypes.TEXT, + korContent: DataTypes.TEXT, + engContent: DataTypes.TEXT, + isActive: { + type: DataTypes.VIRTUAL, + get() { + return ( + new Date(this.createdAt) > Date.now() - 1000 * 60 * 60 * 24 * 14 + ); + }, + }, + isNew: { + type: DataTypes.VIRTUAL, + get() { + return new Date(this.createdAt) > Date.now() - 1000 * 60 * 60 * 24; + }, + }, + }, + { + freezeTableName: true, + charset: "utf8", + collate: "utf8_general_ci", + } + ); + + Petition.associate = function (models) { + Petition.belongsToMany(models.Student, { through: "Student_Petition" }); + }; + + return Petition; +}; diff --git a/src/database/models/Student.js b/src/database/models/Student.js index 8c42854..f431b2e 100644 --- a/src/database/models/Student.js +++ b/src/database/models/Student.js @@ -29,6 +29,7 @@ module.exports = (sequelize, DataTypes) => { Student.hasMany(models.Payment, { foreignKey: "studentId", }); + Student.belongsToMany(models.Petition, { through: "Student_Petition" }); }; return Student; }; diff --git a/src/database/models/payment.js b/src/database/models/payment.js index aba6619..e72fafb 100644 --- a/src/database/models/payment.js +++ b/src/database/models/payment.js @@ -21,7 +21,7 @@ module.exports = (sequelize, DataTypes) => { ); Payment.associate = function (models) { // associations can be defined here - models.Payment.belongsTo(models.Student, { foreignKey: "studentId" }); + Payment.belongsTo(models.Student, { foreignKey: "studentId" }); }; return Payment; }; diff --git a/src/database/models/post.js b/src/database/models/post.js index a2f68e0..b475ef2 100644 --- a/src/database/models/post.js +++ b/src/database/models/post.js @@ -22,10 +22,7 @@ module.exports = (sequelize, DataTypes) => { isNew: { type: DataTypes.VIRTUAL, get() { - const createdAt = this.createdAt; - const createdAtDate = new Date(createdAt); - const now = new Date(); - return createdAtDate.getMinutes() > now.getMinutes() - 60 * 24; + return new Date(this.createdAt) > Date.now() - 1000 * 60 * 60 * 24; }, }, }, diff --git a/src/routes/index.js b/src/routes/index.js index dfa75a0..6a216cf 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -3,6 +3,7 @@ const Router = require("koa-router"); const posts = require("./posts"); const banners = require("./banners"); const boards = require("./boards"); +const petitions = require("./petitions"); const admins = require("./admins"); const auth = require("./auth"); const payments = require("./payments"); @@ -19,6 +20,7 @@ router.use("/posts", posts.routes()); router.use("/admins", admins.routes()); router.use("/banners", banners.routes()); router.use("/boards", boards.routes()); +router.use("/petitions", petitions.routes()); router.use("/payments", payments.routes()); router.use("/cancelRequest", cancelRequest.routes()); diff --git a/src/routes/petitions/index.js b/src/routes/petitions/index.js new file mode 100644 index 0000000..8f29aaa --- /dev/null +++ b/src/routes/petitions/index.js @@ -0,0 +1,10 @@ +const Router = require("koa-router"); +const petitions = new Router(); +const petitionsCtrl = require("./petitions.ctrl"); + +petitions.post("/", petitionsCtrl.write); +petitions.get("/", petitionsCtrl.list); +petitions.get("/:id", petitionsCtrl.read); +petitions.post("/vote/:id", petitionsCtrl.vote); + +module.exports = petitions; diff --git a/src/routes/petitions/petitions.ctrl.js b/src/routes/petitions/petitions.ctrl.js new file mode 100644 index 0000000..fd3f5e6 --- /dev/null +++ b/src/routes/petitions/petitions.ctrl.js @@ -0,0 +1,74 @@ +const models = require("../../database/models"); +const Op = require("sequelize").Op; + +exports.write = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const { id } = ctx.request.user; + const student = await models.Student.findOne({ + where: { id }, + }); + ctx.assert(student, 401); + const petition = ctx.request.body; + const res = await models.Petition.create(petition); + ctx.assert(res, 400); + ctx.status = 204; +}; + +exports.list = async (ctx) => { + const { page } = ctx.request.query; + const PAGE_SIZE = 15; + + ctx.assert(page > 0, 400); + + const offset = PAGE_SIZE * (page - 1); + + const petitions = await models.Petition.findAll({ + order: [["createdAt", "DESC"]], + offset, + limit: PAGE_SIZE, + raw: false, + include: models.Student, + }); + + const petitionCount = await models.Petition.count(); + + const lastPage = Math.ceil(petitionCount / PAGE_SIZE); + + ctx.body = { petitions, lastPage }; +}; + +exports.read = async (ctx) => { + const { id } = ctx.params; + + const petitions = await models.Petition.findOne({ + where: { id }, + raw: false, + include: models.Student, + }); + + ctx.body = petitions; +}; + +exports.vote = async (ctx) => { + ctx.assert(ctx.request.user, 401); + const studentId = ctx.request.user.id; + const student = await models.Student.findOne({ + where: { id: studentId }, + }); + ctx.assert(student, 401); + + const { id } = ctx.params; + + const petition = await models.Petition.findOne({ + where: { id }, + }); + + petition.addStudent(student); + + const result = await Petition.findOne({ + where: { id }, + include: models.Student, + }); + + ctx.body = petition; +}; From ccbc11d7b8a9319a69925d79647b3094ec44b471 Mon Sep 17 00:00:00 2001 From: winningarc Date: Sat, 3 Oct 2020 22:39:45 +0900 Subject: [PATCH 24/26] feat: automatic petition vote when write --- src/routes/petitions/petitions.ctrl.js | 30 ++++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/routes/petitions/petitions.ctrl.js b/src/routes/petitions/petitions.ctrl.js index fd3f5e6..6897268 100644 --- a/src/routes/petitions/petitions.ctrl.js +++ b/src/routes/petitions/petitions.ctrl.js @@ -11,7 +11,9 @@ exports.write = async (ctx) => { const petition = ctx.request.body; const res = await models.Petition.create(petition); ctx.assert(res, 400); - ctx.status = 204; + res.addStudent(student); + ctx.body = res; + ctx.status = 200; }; exports.list = async (ctx) => { @@ -30,11 +32,14 @@ exports.list = async (ctx) => { include: models.Student, }); + console.log(petitions); + const petitionCount = await models.Petition.count(); const lastPage = Math.ceil(petitionCount / PAGE_SIZE); ctx.body = { petitions, lastPage }; + ctx.status = 200; }; exports.read = async (ctx) => { @@ -47,6 +52,7 @@ exports.read = async (ctx) => { }); ctx.body = petitions; + ctx.status = 200; }; exports.vote = async (ctx) => { @@ -61,14 +67,24 @@ exports.vote = async (ctx) => { const petition = await models.Petition.findOne({ where: { id }, + include: models.Student, }); + ctx.assert(petition, 400); - petition.addStudent(student); - - const result = await Petition.findOne({ - where: { id }, - include: models.Student, + console.log(petition); + const exists = petition.Students.some((petitionStudent) => { + console.log(petitionStudent.id); + console.log(studentId); + return petitionStudent.id === studentId; }); - ctx.body = petition; + if (exists) { + ctx.status = 204; + return; + } + + petition.addStudent(student); + + ctx.body = petition.id; + ctx.status = 200; }; From d0cc53818ffc3104c03572f93f607b86e5c9ccc6 Mon Sep 17 00:00:00 2001 From: winningarc Date: Sun, 4 Oct 2020 00:14:10 +0900 Subject: [PATCH 25/26] fix: migration --- package.json | 5 +- .../20201001091755-create-associations.js | 6 +- yarn.lock | 284 ++++++++++-------- 3 files changed, 170 insertions(+), 125 deletions(-) diff --git a/package.json b/package.json index 3693ba5..f7d7a4f 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,12 @@ "homepage": "https://github.com/winningarc/kaist-ua-server#readme", "dependencies": { "@koa/cors": "^3.0.0", + "aws-sdk": "^2.766.0", "cors": "^2.8.5", "crypto": "^1.0.1", "dotenv": "^8.2.0", "jsonwebtoken": "^8.5.1", - "koa": "^2.11.0", + "koa": "^2.13.0", "koa-body": "^4.1.1", "koa-helmet": "^5.2.0", "koa-logger": "^3.2.1", @@ -37,7 +38,7 @@ "passport": "^0.4.1", "passport-accesstoken": "^0.1.0", "router": "^1.3.5", - "sequelize": "^4.44.4", + "sequelize": "^6.3.5", "swagger-jsdoc": "^4.0.0", "yarn": "^1.22.4" }, diff --git a/src/database/migrations/20201001091755-create-associations.js b/src/database/migrations/20201001091755-create-associations.js index 5cbd2d2..9efebfd 100644 --- a/src/database/migrations/20201001091755-create-associations.js +++ b/src/database/migrations/20201001091755-create-associations.js @@ -11,7 +11,8 @@ module.exports = { key: "id", // key in Target model that we're referencing }, onUpdate: "CASCADE", - onDelete: "SET NULL", + onDelete: "RESTRICT", + unique: true, }, PetitionId: { type: Sequelize.UUID, @@ -20,7 +21,8 @@ module.exports = { key: "id", // key in Target model that we're referencing }, onUpdate: "CASCADE", - onDelete: "SET NULL", + onDelete: "RESTRICT", + unique: true, }, createdAt: Sequelize.DATE, updatedAt: Sequelize.DATE, diff --git a/yarn.lock b/yarn.lock index 87fd0e2..cb75ea6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -153,16 +153,6 @@ "@types/events" "*" "@types/node" "*" -"@types/geojson@^1.0.0": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.6.tgz#3e02972728c69248c2af08d60a48cbb8680fffdf" - integrity sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w== - -"@types/geojson@^7946.0.0 || ^1.0.0": - version "7946.0.7" - resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" - integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== - "@types/http-assert@*": version "1.5.1" resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b" @@ -301,7 +291,7 @@ ansicolors@~0.3.2: resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= -any-promise@^1.1.0: +any-promise@^1.1.0, any-promise@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= @@ -331,21 +321,36 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +aws-sdk@^2.766.0: + version "2.766.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.766.0.tgz#f0b05d827c79c78d16efab0520f4ed0c21573665" + integrity sha512-msEEF7veBrxU1TlhLL33du4oJdwJ6uAWogf9+S0v437AX2z6K5IFr5J78JBysBudRHO0L6aC8bat6OS3oPEQvQ== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + binary-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== -bluebird@^3.4.6, bluebird@^3.5.0: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - bowser@2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.9.0.tgz#3bed854233b419b9a7422d9ee3e85504373821c9" @@ -385,6 +390,15 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + bytes@3.1.0, bytes@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -496,14 +510,6 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -cls-bluebird@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cls-bluebird/-/cls-bluebird-2.1.0.tgz#37ef1e080a8ffb55c2f4164f536f1919e7968aee" - integrity sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4= - dependencies: - is-bluebird "^1.0.2" - shimmer "^1.1.0" - co-body@^5.1.1: version "5.2.0" resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124" @@ -627,14 +633,14 @@ dasherize@2.0.0: resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" integrity sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= -debug@2.6.9, debug@^2.2.0, debug@^2.6.9: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.1.0, debug@^3.2.6: +debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -697,7 +703,7 @@ depd@2.0.0, depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -depd@^1.1.0, depd@^1.1.2, depd@~1.1.2: +depd@^1.1.2, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= @@ -789,11 +795,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error-inject@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" - integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= - escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -914,6 +915,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +events@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1002,11 +1008,6 @@ generate-function@^2.3.1: dependencies: is-property "^1.0.2" -generic-pool@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.5.0.tgz#acac4fd743a175ff20574f380910036464cb61f7" - integrity sha512-dEkxmX+egB2o4NR80c/q+xzLLzLX+k68/K8xv81XprD+Sk7ZtP14VugeCz+fUwv5FzpWq40pPtAkzPRqT8ka9w== - get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -1177,7 +1178,7 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== -http-errors@1.7.3, http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.7.2: +http-errors@1.7.3, http-errors@^1.7.3, http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== @@ -1188,6 +1189,17 @@ http-errors@1.7.3, http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@^1.6.3: + version "1.8.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507" + integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + humanize-number@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/humanize-number/-/humanize-number-0.0.2.tgz#11c0af6a471643633588588048f1799541489c18" @@ -1207,6 +1219,11 @@ iconv-lite@^0.5.0: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@1.1.13, ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -1275,11 +1292,6 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-bluebird@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-bluebird/-/is-bluebird-1.0.2.tgz#096439060f4aa411abee19143a84d6a55346d6e2" - integrity sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI= - is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -1362,11 +1374,21 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1530,10 +1552,10 @@ koa2-swagger-ui@^4.0.1: lodash "^4.17.15" read-pkg-up "^7.0.1" -koa@^2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.11.0.tgz#fe5a51c46f566d27632dd5dc8fd5d7dd44f935a4" - integrity sha512-EpR9dElBTDlaDgyhDMiLkXrPwp6ZqgAIBvhhmxQ9XN4TFgW+gEz6tkcsNI6BnUbUftrKDjVFj4lW2/J2aNBMMA== +koa@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.0.tgz#25217e05efd3358a7e5ddec00f0a380c9b71b501" + integrity sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ== dependencies: accepts "^1.3.5" cache-content-type "^1.0.0" @@ -1545,7 +1567,6 @@ koa@^2.11.0: depd "^1.1.2" destroy "^1.0.4" encodeurl "^1.0.2" - error-inject "^1.0.0" escape-html "^1.0.3" fresh "~0.5.2" http-assert "^1.3.0" @@ -1632,11 +1653,6 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash@^4.17.1: - version "4.17.19" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" - integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== - lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" @@ -1704,17 +1720,17 @@ methods@^1.1.2, methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -mime-db@1.43.0: - version "1.43.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" - integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== mime-types@^2.1.18, mime-types@~2.1.24: - version "2.1.26" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" - integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== dependencies: - mime-db "1.43.0" + mime-db "1.44.0" mimic-fn@^3.0.0: version "3.1.0" @@ -1745,7 +1761,7 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.5" -moment-timezone@^0.5.14: +moment-timezone@^0.5.31: version "0.5.31" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.31.tgz#9c40d8c5026f0c7ab46eda3d63e49c155148de05" integrity sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA== @@ -1757,10 +1773,10 @@ moment-timezone@^0.5.14: resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== -moment@^2.20.0: - version "2.27.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" - integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== +moment@^2.26.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.0.tgz#fcbef955844d91deb55438613ddcec56e86a3425" + integrity sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA== ms@2.0.0: version "2.0.0" @@ -2072,6 +2088,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -2089,6 +2110,11 @@ qs@^6.4.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + raw-body@^2.2.0: version "2.4.1" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" @@ -2185,13 +2211,12 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -retry-as-promised@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-2.3.2.tgz#cd974ee4fd9b5fe03cbf31871ee48221c07737b7" - integrity sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c= +retry-as-promised@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-3.2.0.tgz#769f63d536bec4783549db0777cb56dadd9d8543" + integrity sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg== dependencies: - bluebird "^3.4.6" - debug "^2.6.9" + any-promise "^1.3.0" rimraf@2.6.3: version "2.6.3" @@ -2228,6 +2253,16 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + semver-diff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -2235,7 +2270,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -2245,7 +2280,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1: +semver@^7.2.1, semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== @@ -2255,28 +2290,29 @@ seq-queue@^0.0.5: resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" integrity sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4= -sequelize@^4.44.4: - version "4.44.4" - resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-4.44.4.tgz#9607eaa3e59080d27d8b17481d2e449e87e58f18" - integrity sha512-nkHmYkbwQK7uwpgW9VBalCBnQqQ8mslTdgcBthtJLORuPvAYRPlfkXZMVUU9TLLJt9CX+/y0MYg0DpcP6ywsEQ== +sequelize-pool@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668" + integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg== + +sequelize@^6.3.5: + version "6.3.5" + resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.3.5.tgz#80e3db7ac8b76d98c45ca93334197eb6e2335158" + integrity sha512-MiwiPkYSA8NWttRKAXdU9h0TxP6HAc1fl7qZmMO/VQqQOND83G4nZLXd0kWILtAoT9cxtZgFqeb/MPYgEeXwsw== dependencies: - bluebird "^3.5.0" - cls-bluebird "^2.1.0" - debug "^3.1.0" - depd "^1.1.0" + debug "^4.1.1" dottie "^2.0.0" - generic-pool "3.5.0" inflection "1.12.0" - lodash "^4.17.1" - moment "^2.20.0" - moment-timezone "^0.5.14" - retry-as-promised "^2.3.2" - semver "^5.5.0" - terraformer-wkt-parser "^1.1.2" + lodash "^4.17.15" + moment "^2.26.0" + moment-timezone "^0.5.31" + retry-as-promised "^3.2.0" + semver "^7.3.2" + sequelize-pool "^6.0.0" toposort-class "^1.0.1" - uuid "^3.2.1" - validator "^10.4.0" - wkx "^0.4.1" + uuid "^8.1.0" + validator "^10.11.0" + wkx "^0.5.0" setprototypeof@1.1.1: version "1.1.1" @@ -2300,11 +2336,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shimmer@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -2454,21 +2485,6 @@ term-size@^2.1.0: resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== -terraformer-wkt-parser@^1.1.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/terraformer-wkt-parser/-/terraformer-wkt-parser-1.2.1.tgz#8041e2aeb0c9f2b4cbbec8ec2c5c00c45ddfee02" - integrity sha512-+CJyNLWb3lJ9RsZMTM66BY0MT3yIo4l4l22Jd9CrZuwzk54fsu4Sc7zejuS9fCITTuTQy3p06d4MZMVI7v5wSg== - dependencies: - "@types/geojson" "^1.0.0" - terraformer "~1.0.5" - -terraformer@~1.0.5: - version "1.0.12" - resolved "https://registry.yarnpkg.com/terraformer/-/terraformer-1.0.12.tgz#39e08f9c753606421acce02e122440c72dfa12d3" - integrity sha512-MokUp0+MFal4CmJDVL6VAO1bKegeXcBM2RnPVfqcFIp2IIv8EbPAjG0j/vEy/vuKB8NVMMSF2vfpVS/QLe4DBg== - optionalDependencies: - "@types/geojson" "^7946.0.0 || ^1.0.0" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2602,15 +2618,28 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.2.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +uuid@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" + integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== v8-compile-cache@^2.0.3: version "2.1.1" @@ -2625,7 +2654,7 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -validator@^10.4.0: +validator@^10.11.0: version "10.11.0" resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== @@ -2654,10 +2683,10 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -wkx@^0.4.1: - version "0.4.8" - resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.4.8.tgz#a092cf088d112683fdc7182fd31493b2c5820003" - integrity sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ== +wkx@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" + integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== dependencies: "@types/node" "*" @@ -2703,6 +2732,19 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" From 407160f29b5912d461a1e7795c07aaeeb2e3df64 Mon Sep 17 00:00:00 2001 From: winningarc Date: Sun, 4 Oct 2020 22:25:52 +0900 Subject: [PATCH 26/26] feat: add key to register --- src/database/migrations/20201001091755-create-associations.js | 2 +- src/routes/admins/admins.ctrl.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/database/migrations/20201001091755-create-associations.js b/src/database/migrations/20201001091755-create-associations.js index 9efebfd..66bab24 100644 --- a/src/database/migrations/20201001091755-create-associations.js +++ b/src/database/migrations/20201001091755-create-associations.js @@ -3,7 +3,7 @@ module.exports = { up: async (queryInterface, Sequelize) => { // Board hasMany Post - return queryInterface.createTable("Student_Petition", { + await queryInterface.createTable("Student_Petition", { StudentId: { type: Sequelize.UUID, references: { diff --git a/src/routes/admins/admins.ctrl.js b/src/routes/admins/admins.ctrl.js index e4269a7..72446f0 100644 --- a/src/routes/admins/admins.ctrl.js +++ b/src/routes/admins/admins.ctrl.js @@ -197,7 +197,8 @@ exports.check = async (ctx) => { * description: Internal Server Error */ exports.register = async (ctx) => { - const { email, password } = ctx.request.body; + const { email, password, key } = ctx.request.body; + ctx.assert(key === process.env.ADMIN_KEY, 404); const res = await models.Admin.findOne({ where: { email } }); ctx.assert(!res, 400); var salt = genRandomString(16);