Toggle navigation
Toggle navigation
This project
Loading...
Sign in
2019-1-OpenSourceSW
/
WhoAreYou
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
서주원
2018-12-14 13:42:35 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
d5ce6f3dba4fcd76175aa3cf16680b531a7b3ddf
d5ce6f3d
1 parent
5198b035
Final commit
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
92 additions
and
53 deletions
api/card/addCards.js
api/card/getCardId.js
api/card/getResult.js
api/card/setOpponentClass.js
api/deck/addDeck.js
api/deck/crawlerDeckCodes.js
api/deck/getDeckId.js
api/deck/newDeck.js
api/user/findById.js
api/user/login.js
api/user/signUp.js
views/html/decklist.html
views/html/result.html
api/card/addCards.js
View file @
d5ce6f3
...
...
@@ -5,20 +5,19 @@ let cardEnUS=[]
let
cardKoKR
=
[]
//카드 덱 ID와 카드 정보를 받아와, 카드별로 dbfId랑 매칭 시킨 후, card 테이블에 추가
//return: 없음
exports
.
AddCards
=
(
deckId
,
cards
)
=>
{
fs
.
readFile
(
'cardskoKR.json'
,(
err
,
data
)
=>
{
if
(
err
)
throw
err
cardKoKR
=
JSON
.
parse
(
data
)
})
return
new
Promise
((
resolve
,
reject
)
=>
{
//전체 카드 읽어 오기
fs
.
readFile
(
'cardsenUS.json'
,(
err
,
data
)
=>
{
if
(
err
)
throw
err
cardEnUS
=
JSON
.
parse
(
data
)
//mysql 연결
mysql
.
getConnection
((
err
,
connection
)
=>
{
if
(
err
)
throw
err
//카드별로 dbfId 찾기
for
(
let
i
=
0
;
i
<
cards
.
length
;
i
++
)
{
let
cardCost
=
cards
[
i
].
cardCost
let
cardName
=
cards
[
i
].
cardName
...
...
@@ -27,12 +26,13 @@ exports.AddCards=(deckId,cards)=>{
for
(
let
i
=
0
;
i
<
cardEnUS
.
length
;
i
++
)
{
if
(
cardEnUS
[
i
].
name
===
cardName
)
{
cardId
=
cardEnUS
[
i
].
dbfId
//single quote 처리
cardName
=
cardName
.
replace
(
'\''
,
'\'\''
)
break
}
}
//카드 추가
connection
.
query
(
`insert into card (deckId,cardId,cardCost,cardName,cardNum) values (\'
${
deckId
}
\',\'
${
cardId
}
\',\'
${
cardCost
}
\',\'
${
cardName
}
\',\'
${
cardNum
}
\')`
,
(
err
,
results
,
fields
)
=>
{
//
if
(
err
)
throw
err
})
}
...
...
api/card/getCardId.js
View file @
d5ce6f3
const
mysql
=
require
(
'../../database/mysql'
)
//덱 ID를 바탕으로 해당 덱에 속해있는 모든 카드 반환
//return: json array
exports
.
GetCardId
=
(
deckId
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
mysql
.
getConnection
((
err
,
connection
)
=>
{
...
...
api/card/getResult.js
View file @
d5ce6f3
...
...
@@ -5,9 +5,13 @@ const fs=require('fs')
const
ejs
=
require
(
'ejs'
)
let
globalMulligan
let
globalDecks
//result.ejs 렌더링 전 수행됨. 현재 덱 ID와 상대 직업을 가지고 상대의 점유율 상위 3개 덱과, 내 덱의 추천 멀리건 출력
//return : 렌더링 된 result.ejs
exports
.
GetResult
=
(
req
,
res
)
=>
{
const
deckId
=
req
.
session
.
deckId
const
opponentClass
=
req
.
session
.
opponentClass
//덱 ID와 상대 직업 정보 체크
const
DataCheck
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
deckId
||
!
opponentClass
){
...
...
@@ -19,13 +23,15 @@ exports.GetResult=(req,res)=>{
resolve
()
})
}
//현재 덱ID를 바탕으로 카드정보 가져오기
const
GetCardId
=
()
=>
{
return
getCardId
.
GetCardId
(
deckId
)
}
//가져온 카드 정보를 바탕으로, hsreplay.net에서, 덱 검색하기, 검색한 결과의 html을 반환
const
GetMulContent
=
(
cardIds
)
=>
{
cardIds
=
JSON
.
stringify
(
cardIds
)
cardIds
=
JSON
.
parse
(
cardIds
)
//검색을 위한 쿼리스트링
let
idInQuery
=
cardIds
[
0
].
cardId
for
(
let
i
=
1
;
i
<
cardIds
.
length
;
i
++
){
idInQuery
+=
'%2C'
+
cardIds
[
i
].
cardId
...
...
@@ -50,7 +56,7 @@ exports.GetResult=(req,res)=>{
resolve
(
asyncFunc
())
})
}
//검색한 html을 가지고, 검색결과로 부터 덱의 url 파싱
const
GetDeckHref
=
(
content
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
$
=
cheerio
.
load
(
content
)
...
...
@@ -60,6 +66,7 @@ exports.GetResult=(req,res)=>{
resolve
(
deckHref
)
})
}
//덱의 url을 이용, 해당 덱의 정보를 나타내는 페이지 불러온 후 html로 반환
const
GetDeckContent
=
(
href
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
asyncFunc
=
async
()
=>
{
...
...
@@ -81,6 +88,7 @@ exports.GetResult=(req,res)=>{
resolve
(
asyncFunc
())
})
}
//받아온 html에서 카드 이름과 멀리건 부분 추출
const
GetMulligan
=
(
content
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
$
=
cheerio
.
load
(
content
)
...
...
@@ -90,17 +98,20 @@ exports.GetResult=(req,res)=>{
for
(
let
i
=
0
;
i
<
cardNames
.
length
;
i
++
){
let
cardName
=
$
(
cardNames
[
i
]).
text
()
let
cardWinRate
=
$
(
cardWinRates
[
6
*
i
]).
text
()
//문자 삭제하고, 멀리건의 승률이 숫자로만 나타나도록
cardWinRate
=
cardWinRate
.
replace
(
'▼'
,
''
)
cardWinRate
=
cardWinRate
.
replace
(
'▲'
,
''
)
cardWinRate
=
cardWinRate
.
replace
(
'%'
,
''
)
cards
.
push
({
cardName
:
cardName
,
cardWinRate
:
cardWinRate
})
}
//카드를 멀리건 승률 순서대로 정렬
cards
.
sort
((
a
,
b
)
=>
{
return
a
.
cardWinRate
<
b
.
cardWinRate
?
1
:
-
1
})
resolve
(
cards
)
})
}
//상대 직업을 가지고 hsreplay.net에서 검색, html로 반환
const
GetOppContent
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
asyncFunc
=
async
()
=>
{
...
...
@@ -122,7 +133,7 @@ exports.GetResult=(req,res)=>{
resolve
(
asyncFunc
())
})
}
//받아온 html로부터 덱의 이름, 게임 횟수 추출
const
GetDeckInfo
=
(
content
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
$
=
cheerio
.
load
(
content
)
...
...
api/card/setOpponentClass.js
View file @
d5ce6f3
//result 출력 전, 선택한 상대 직업을 세션에 저장
//return: response status code
exports
.
SetOpponentClass
=
(
req
,
res
)
=>
{
const
opponentClass
=
req
.
body
.
opponentClass
const
DataCheck
=
()
=>
{
...
...
api/deck/addDeck.js
View file @
d5ce6f3
const
mysql
=
require
(
'../../database/mysql'
)
//덱 추가
//return: 없음
exports
.
AddDeck
=
(
deckOwner
,
deckTitle
,
deckCode
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
mysql
.
getConnection
((
err
,
connection
)
=>
{
...
...
@@ -7,7 +8,7 @@ exports.AddDeck=(deckOwner,deckTitle,deckCode)=>{
connection
.
query
(
`insert into deck (deckOwner,deckTitle,deckCode) values (\'
${
deckOwner
}
\',\'
${
deckTitle
}
\',\'
${
deckCode
}
\');`
,
(
err
,
results
,
fields
)
=>
{
if
(
err
)
throw
err
connection
.
release
()
resolve
(
results
)
resolve
()
})
})
})
...
...
api/deck/crawlerDeckCodes.js
View file @
d5ce6f3
...
...
@@ -2,6 +2,8 @@ const request=require('request')
const
iconv
=
require
(
'iconv-lite'
)
const
charset
=
require
(
'charset'
)
//덱 추가시 deck.codes로부터 덱 코드가 의미하는 덱 정보 페이지 크롤링
//return: html
exports
.
Crawl
=
(
deckCode
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
request
({
...
...
api/deck/getDeckId.js
View file @
d5ce6f3
const
mysql
=
require
(
'../../database/mysql'
)
//덱의 주인과 덱 이름을 가지고 DeckId값 반환
//return: deckId
exports
.
GetDeckId
=
(
deckOwner
,
deckTitle
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
mysql
.
getConnection
((
err
,
connection
)
=>
{
if
(
err
)
throw
err
connection
.
query
(
`select * from deck where deckOwner=\'
${
deckOwner
}
\' and deckTitle=\'
${
deckTitle
}
\'`
,(
err
,
results
,
field
)
=>
{
if
(
err
)
throw
err
//console.log('result in getDeckId'+results[0])
connection
.
release
()
resolve
(
results
[
0
].
id
)
})
...
...
api/deck/newDeck.js
View file @
d5ce6f3
...
...
@@ -4,13 +4,16 @@ const addCards=require('../card/addCards')
const
addDeck
=
require
(
'./addDeck'
)
const
getDeckId
=
require
(
'./getDeckId'
)
//새로운 덱 추가
//return : response status code
exports
.
NewDeck
=
(
req
,
res
)
=>
{
const
deckOwner
=
req
.
session
.
sid
//덱 이름이 주어지지 않았다면 시간으로 저장
const
deckTitle
=
req
.
body
.
deckTitle
||
new
Date
()
let
deckCode
=
req
.
body
.
deckCode
let
cards
=
[]
//덱 코드가 입력 되었는지 체크
const
DataCheck
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
deckCode
){
...
...
@@ -22,32 +25,39 @@ exports.NewDeck=(req,res)=>{
else
resolve
()
})
}
//덱 코드를 가지고 deck.codes 크롤링, 성공시 html을 reolve해줌
const
CrawlPage
=
()
=>
{
return
crawler
.
Crawl
(
deckCode
)
}
//받아온 html로부터 덱을 구성하는 카드정보 추출
const
DeckCrawl
=
(
result
)
=>
{
const
$
=
cheerio
.
load
(
result
)
//카드의 코스트 배열
let
cardCosts
=
$
(
'div.hs-tile-info'
).
children
(
'.hs-tile-info-left.mdc-list-item__start-detail'
)
//카드의 이름 배열
let
cardNames
=
$
(
'div.hs-tile-info'
).
find
(
'span'
).
find
(
'span'
)
//카드가 들어간 개수 배열
let
cardNums
=
$
(
'div.hs-tile-info'
).
children
(
'.hs-tile-info-right.mdc-list-item__end-detail'
)
for
(
let
i
=
0
;
i
<
cardNames
.
length
;
i
++
)
{
let
cardCost
=
$
(
cardCosts
[
i
]).
text
()
let
cardName
=
$
(
cardNames
[
i
]).
text
()
let
cardNum
=
$
(
cardNums
[
i
]).
text
()
//카드의 개수가 1개라면, 웹에서는 카드의 개수를 공백으로 표현함.
//카드의 개수가 1개가 아니라 2개여도 양 옆 공백이 상당하기 때문에,
//trim()을 우선 사용하고, 결과에 대해서 문자열을 다듬음
if
(
cardNum
.
trim
()
===
''
)
cardNum
=
'1'
else
cardNum
=
cardNum
.
trim
()
cards
.
push
({
cardCost
:
cardCost
,
cardName
:
cardName
,
cardNum
:
cardNum
})
}
//console.log(cards)
}
//deck 테이블에 새로운 row 추가
const
AddDeck
=
()
=>
{
const
asyncAddDeck
=
async
()
=>
{
try
{
const
results
=
await
addDeck
.
AddDeck
(
deckOwner
,
deckTitle
,
deckCode
)
await
addDeck
.
AddDeck
(
deckOwner
,
deckTitle
,
deckCode
)
}
catch
(
err
)
{
throw
err
...
...
@@ -55,7 +65,7 @@ exports.NewDeck=(req,res)=>{
}
return
asyncAddDeck
()
}
//카드를 추가하기 위해 방금 추가한 덱 id를 가져옴
const
GetId
=
()
=>
{
const
asyncGetDeckId
=
async
()
=>
{
try
{
...
...
@@ -68,6 +78,7 @@ exports.NewDeck=(req,res)=>{
}
return
asyncGetDeckId
()
}
//card 테이블에 새로운 여러개의 row 추가
const
AddCards
=
(
deckId
)
=>
{
return
addCards
.
AddCards
(
deckId
,
cards
)
}
...
...
api/user/findById.js
View file @
d5ce6f3
const
mysql
=
require
(
'../../database/mysql'
)
//사용자의 아이디를 가지고 유저 검색,
//return: 사용자가 있으면, 사용자 정보
// 사용자가 없으면, 없음
exports
.
findById
=
(
userId
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
mysql
.
getConnection
((
err
,
connection
)
=>
{
...
...
api/user/login.js
View file @
d5ce6f3
const
findById
=
require
(
'./findById'
)
const
bcrypt
=
require
(
'bcrypt-nodejs'
)
//입력한 아이디와 비밀번호를 가지고 로그인
exports
.
Login
=
(
req
,
res
)
=>
{
const
userId
=
req
.
body
.
userId
const
password
=
req
.
body
.
password
//아이디와 비밀번호가 존재 하는지 체크
const
DataCheck
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
userId
||
!
password
){
...
...
@@ -16,7 +17,7 @@ exports.Login=(req,res)=>{
else
resolve
()
})
}
//이 아이디로 등록된 사용자가 있는 지 체크
const
IdCheck
=
()
=>
{
let
user
=
{}
const
findUser
=
async
()
=>
{
...
...
@@ -30,7 +31,7 @@ exports.Login=(req,res)=>{
}
return
findUser
()
}
//해당 유저의 비밀번호와 입력된 비밀번호가 같은 지 체크
const
PwCheck
=
(
user
)
=>
{
if
(
user
[
0
]
==
null
){
return
Promise
.
reject
({
...
...
@@ -38,6 +39,7 @@ exports.Login=(req,res)=>{
message
:
'id wrong'
})
}
//암호화 모듈을 사용했기 때문에, 서로 비교하는 함수를 써야함
if
(
bcrypt
.
compareSync
(
password
,
user
[
0
].
password
)){
req
.
session
.
sid
=
userId
req
.
session
.
save
(()
=>
{
...
...
api/user/signUp.js
View file @
d5ce6f3
const
findById
=
require
(
'./findById'
)
const
mysql
=
require
(
'../../database/mysql'
)
const
bcrypt
=
require
(
'bcrypt-nodejs'
)
//입력된 아이디와 비밀번호를 가지고 회원가입.
//비밀번호 확인은 프론트 단에서 이루어 졌음.
//return: response status code
exports
.
SignUp
=
(
req
,
res
)
=>
{
const
userId
=
req
.
body
.
userId
const
password
=
req
.
body
.
password
//아이디와 비밀번호가 존재하는 지 체크
const
DataCheck
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
userId
||
!
password
){
...
...
@@ -16,6 +19,7 @@ exports.SignUp=(req,res)=>{
else
resolve
()
})
}
//해당 아이디로 등록한 회원이 있는 지 체크
const
UserCheck
=
()
=>
{
let
user
=
{}
const
findUser
=
async
()
=>
{
...
...
@@ -29,7 +33,7 @@ exports.SignUp=(req,res)=>{
}
return
findUser
()
}
//아이디가 중복되지 않았다면 회원가입 진행
const
SignUp
=
(
user
)
=>
{
if
(
user
[
0
]
!=
null
){
return
Promise
.
reject
({
...
...
@@ -37,6 +41,7 @@ exports.SignUp=(req,res)=>{
message
:
'User Already Exists'
})
}
//비밀번호는 암호화 하여 데이터베이스에 저장
const
hash
=
bcrypt
.
hashSync
(
password
,
bcrypt
.
genSaltSync
(
10
),
null
)
mysql
.
getConnection
((
err
,
connection
)
=>
{
if
(
err
)
throw
err
...
...
views/html/decklist.html
View file @
d5ce6f3
...
...
@@ -45,7 +45,7 @@
<span
class=
"icon-bar"
></span>
<span
class=
"icon-bar"
></span>
</button>
<a
class=
"navbar-brand"
href=
"/"
>
Who Are You?
</a>
<a
class=
"navbar-brand"
href=
"/
main
"
>
Who Are You?
</a>
</div>
<div
class=
"navbar-collapse collapse"
id=
"navbar"
aria-expanded=
"false"
style=
"height: 1px;"
>
<ul
class=
"nav navbar-nav"
>
...
...
views/html/result.html
View file @
d5ce6f3
...
...
@@ -18,32 +18,6 @@
<script
src=
"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"
></script>
<script>
$
(
document
).
ready
(
function
(){
let
mulligan
,
opponentDecks
$
.
ajax
({
type
:
'GET'
,
url
:
'/api/card/getmulligan'
,
success
:
function
(
result
){
mulligan
=
result
$
(
'#yourMulligan'
).
add
(
'<ul>'
)
for
(
let
i
=
0
;
i
<
mulligan
.
length
;
i
++
){
$
(
'#yourMulligan'
).
add
(
`<li><h4>카드 이름:
${
mulligan
[
i
][
'cardName'
]}
</h4><br><h5>멀리건 승률:
${
mulligan
[
i
][
'cardWinRate'
]}
</h5></li>`
)
}
$
(
'#yourMulligan'
).
add
(
'</ul>'
)
}
})
$
.
ajax
({
type
:
'GET'
,
url
:
'/api/card/getopponent'
,
success
:
function
(
result
){
opponentDecks
=
result
$
(
'#opponentDecks'
).
add
(
'<ul>'
)
for
(
let
i
=
0
;
i
<
opponentDecks
.
length
;
i
++
){
$
(
'#opponentDecks'
).
add
(
`<li><h4>덱 이름:
${
opponentDecks
[
i
][
'deckTitle'
]}
</h4><br><h5>30일간 플레이 수:
${
opponentDecks
[
i
][
'deckGame'
]}
</h5></li>`
)
}
$
(
'#opponentDecks'
).
add
(
'</ul>'
)
}
})
$
(
'#logoutButton'
).
click
(
function
(){
$
.
ajax
({
type
:
'POST'
,
...
...
@@ -91,11 +65,37 @@
<br>
<br>
<h3
class=
"form-signin-heading"
>
상대편의 주요 덱
</h3>
<div
id=
"opponentDecks"
></div>
<div
id=
"opponentDecks"
>
<table
class=
"table"
style=
"text-align: center;"
>
<thead>
<td>
덱 이름
</td>
<td>
플레이 수
</td>
</thead>
<tbody>
<tr>
<td><a
class=
"list-group-item"
>
덱이름1
</a></td>
<td><a
class=
"list-group-item"
>
10000
</a></td>
</tr>
</tbody>
</table>
</div>
<br>
<br>
<h3
class=
"form-signin-heading"
>
내 덱의 추천 멀리건
</h3>
<div
id=
"yourMulligan"
></div>
<div
id=
"yourMulligan"
>
<table
class=
"table"
style=
"text-align: center;"
>
<thead>
<td>
카드 이름
</td>
<td>
멀리건 승률
</td>
</thead>
<tbody>
<tr>
<td><a
class=
"list-group-item"
>
카드이름1
</a></td>
<td><a
class=
"list-group-item"
>
59.8
</a></td>
</tr>
</tbody>
</table>
</div>
<br>
<br>
<div
class=
"row"
>
...
...
Please
register
or
login
to post a comment