Showing
41 changed files
with
823 additions
and
345 deletions
LICENCE
0 → 100644
1 | + | ||
2 | +MIT License | ||
3 | + | ||
4 | +Copyright (c) 2020 Yong-Woo Song | ||
5 | + | ||
6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | +of this software and associated documentation files (the "Software"), to deal | ||
8 | +in the Software without restriction, including without limitation the rights | ||
9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | +copies of the Software, and to permit persons to whom the Software is | ||
11 | +furnished to do so, subject to the following conditions: | ||
12 | + | ||
13 | +The above copyright notice and this permission notice shall be included in all | ||
14 | +copies or substantial portions of the Software. | ||
15 | + | ||
16 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | +SOFTWARE. | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
No preview for this file type
No preview for this file type
1 | +# Jaksimsamil | ||
2 | + | ||
3 | + | ||
4 | + | ||
5 | + | ||
6 | + | ||
7 | + | ||
8 | +## Project Overview | ||
9 | + | ||
10 | +> **Jaksaimsamil Algorithm Study Helper Service** | ||
11 | +> | ||
12 | +> 작심삼일 알고리즘 문제풀이 도우미 서비스<br/> | ||
13 | +> | ||
14 | +> > 알고리즘 문제 풀이 스터디를 꾸준히 할 수 있게 돕는 웹 서비스입니다. | ||
15 | +> > <br> [링크](http://facerain.dcom.club)에서 직접 사용해 보세요! | ||
16 | + | ||
17 | + | ||
18 | + | ||
19 | + | ||
20 | + | ||
21 | +## Features (ver.1.0.0) | ||
22 | + | ||
23 | +- 회원가입/로그인 제공 | ||
24 | +- Online Judge 연동 가능 (Baekjoon) | ||
25 | +- 나의 학습 현황 한눈에 보기 | ||
26 | +- 추천 문제 제공 | ||
27 | +- Slack 알리미 | ||
28 | + | ||
29 | +## Upcoming Features | ||
30 | + | ||
31 | +- 친구 추가 | ||
32 | +- 친구와의 경쟁 | ||
33 | +- 그룹 추가 | ||
34 | +- 그룹 추천 | ||
35 | +- 개선된 문제 추천 (사용자 실력 맞춤형) | ||
36 | + | ||
37 | +## Usages | ||
38 | + | ||
39 | +#### 회원 | ||
40 | + | ||
41 | +1. 로그인하여 서비스에 접속 할 수 있습니다. | ||
42 | +2. 서비스가 처음이라면, 회원가입을 하세요. | ||
43 | + <br> | ||
44 | + | ||
45 | +#### 설정 | ||
46 | + | ||
47 | +1. 백준 아이디를 등록하고 동기화하세요. [상세]() | ||
48 | +2. 슬랙 HOOK URL을 등록하세요. [상세]() | ||
49 | +3. 일일 목표량을 등록하세요. | ||
50 | + | ||
51 | +## Getting Started | ||
52 | + | ||
53 | +1. Clone | ||
54 | + | ||
55 | +``` | ||
56 | +git clone https://github.com/FacerAin/OSS-Jaksimsamil.git | ||
57 | +``` | ||
58 | + | ||
59 | +2. Install MongoDB(Ubuntu) | ||
60 | + | ||
61 | +``` | ||
62 | +sudo apt-get update | ||
63 | +sudo apt-get install -y mongodb-org | ||
64 | +sudo service mongod start | ||
65 | +``` | ||
66 | + | ||
67 | +3. Set Serverfile | ||
68 | + | ||
69 | +``` | ||
70 | +cd Jaksimsamil-server | ||
71 | +touch .env | ||
72 | +---TYPE THIS IN FILE---- | ||
73 | +SERVER_PORT= ### | ||
74 | +MONGO_URL= ### | ||
75 | +JWT_SECRET= ### | ||
76 | +``` | ||
77 | + | ||
78 | +4. Start Node Server | ||
79 | + | ||
80 | +``` | ||
81 | +cd Jaksimsamil-server | ||
82 | +sudo npm install | ||
83 | +npm start | ||
84 | +``` | ||
85 | + | ||
86 | +[링크](/jaksimsamil-server/README.md)에서 API 제공 목록을 볼 수 있습니다. | ||
87 | +<br> | ||
88 | + | ||
89 | +5. Set Front-end page | ||
90 | + | ||
91 | +``` | ||
92 | +cd Jaksimsamil-server | ||
93 | +sudo npm install | ||
94 | +npm start #Start React | ||
95 | +``` | ||
96 | + | ||
97 | +## Contributing | ||
98 | + | ||
99 | +컨트리뷰션은 언제나 환영입니다. 다음 절차를 지켜주세요! | ||
100 | + | ||
101 | +1. Fork the Project | ||
102 | +2. Create your Feature Branch | ||
103 | +3. Commit our changes | ||
104 | +4. Push to Branch | ||
105 | +5. Open a Pull Request | ||
106 | + | ||
107 | +## License | ||
108 | + | ||
109 | +- MIT LICENCE | ... | ... |
SECURITY.md
0 → 100644
1 | +# Security Policy | ||
2 | + | ||
3 | +## Supported Versions | ||
4 | + | ||
5 | +Use this section to tell people about which versions of your project are | ||
6 | +currently being supported with security updates. | ||
7 | + | ||
8 | +| Version | Supported | | ||
9 | +| ------- | ------------------ | | ||
10 | +| 5.1.x | :white_check_mark: | | ||
11 | +| 5.0.x | :x: | | ||
12 | +| 4.0.x | :white_check_mark: | | ||
13 | +| < 4.0 | :x: | | ||
14 | + | ||
15 | +## Reporting a Vulnerability | ||
16 | + | ||
17 | +Use this section to tell people how to report a vulnerability. | ||
18 | + | ||
19 | +Tell them where to go, how often they can expect to get an update on a | ||
20 | +reported vulnerability, what to expect if the vulnerability is accepted or | ||
21 | +declined, etc. |
This diff could not be displayed because it is too large.
... | @@ -16,7 +16,7 @@ | ... | @@ -16,7 +16,7 @@ |
16 | "react-dom": "^16.13.1", | 16 | "react-dom": "^16.13.1", |
17 | "react-redux": "^7.2.0", | 17 | "react-redux": "^7.2.0", |
18 | "react-router-dom": "^5.2.0", | 18 | "react-router-dom": "^5.2.0", |
19 | - "react-scripts": "3.4.1", | 19 | + "react-scripts": "^3.4.3", |
20 | "redux": "^4.0.5", | 20 | "redux": "^4.0.5", |
21 | "redux-actions": "^2.6.5", | 21 | "redux-actions": "^2.6.5", |
22 | "redux-devtools-extension": "^2.13.8", | 22 | "redux-devtools-extension": "^2.13.8", | ... | ... |
... | @@ -3,42 +3,111 @@ import { makeStyles } from '@material-ui/core/styles'; | ... | @@ -3,42 +3,111 @@ import { makeStyles } from '@material-ui/core/styles'; |
3 | import Paper from '@material-ui/core/Paper'; | 3 | import Paper from '@material-ui/core/Paper'; |
4 | import Grid from '@material-ui/core/Grid'; | 4 | import Grid from '@material-ui/core/Grid'; |
5 | import palette from '../../lib/styles/palette'; | 5 | import palette from '../../lib/styles/palette'; |
6 | +import AuthForm from '../auth/AuthForm'; | ||
6 | const useStyles = makeStyles((theme) => ({ | 7 | const useStyles = makeStyles((theme) => ({ |
7 | root: { | 8 | root: { |
8 | flexGrow: 1, | 9 | flexGrow: 1, |
9 | background: palette.gray[2], | 10 | background: palette.gray[2], |
11 | + padding: theme.spacing(8), | ||
10 | }, | 12 | }, |
11 | paper: { | 13 | paper: { |
12 | - padding: theme.spacing(2), | 14 | + padding: theme.spacing(8), |
15 | + margin: 'auto', | ||
13 | textAlign: 'center', | 16 | textAlign: 'center', |
14 | color: theme.palette.text.secondary, | 17 | color: theme.palette.text.secondary, |
15 | }, | 18 | }, |
16 | })); | 19 | })); |
17 | -const HomeForm = () => { | 20 | +const HomeForm = ({ PSdata, goalNum }) => { |
18 | const classes = useStyles(); | 21 | const classes = useStyles(); |
19 | - return ( | 22 | + return PSdata ? ( |
20 | <div className={classes.root}> | 23 | <div className={classes.root}> |
21 | - <Grid container spacing={3}> | 24 | + <Grid container spacing={5}> |
22 | <Grid item xs={12}> | 25 | <Grid item xs={12}> |
23 | - <Paper className={classes.paper}>xs=12</Paper> | 26 | + <Paper className={classes.paper}> |
27 | + <h1>{PSdata.recommend_data.problem_number}</h1> | ||
28 | + <h1>{PSdata.recommend_data.problem_title}</h1> | ||
29 | + <a | ||
30 | + href={'http://www.boj.kr/' + PSdata.recommend_data.problem_number} | ||
31 | + > | ||
32 | + 바로가기 | ||
33 | + </a> | ||
34 | + | ||
35 | + <h3>오늘의 추천 문제</h3> | ||
36 | + </Paper> | ||
37 | + </Grid> | ||
38 | + <Grid item xs={6}> | ||
39 | + <Paper className={classes.paper}> | ||
40 | + <h1>{PSdata.presentNum + '/' + goalNum}</h1> | ||
41 | + <h3>오늘 푼 문제</h3> | ||
42 | + </Paper> | ||
24 | </Grid> | 43 | </Grid> |
25 | <Grid item xs={6}> | 44 | <Grid item xs={6}> |
26 | - <Paper className={classes.paper}>xs=6</Paper> | 45 | + <Paper className={classes.paper}> |
46 | + <h1>{PSdata.latestSolve.problem_number}</h1> | ||
47 | + <h1>{PSdata.latestSolve.problem_title}</h1> | ||
48 | + <h3>마지막으로 푼 문제</h3> | ||
49 | + </Paper> | ||
50 | + </Grid> | ||
51 | + | ||
52 | + <Grid item xs={4}> | ||
53 | + <Paper className={classes.paper}> | ||
54 | + <h1>{PSdata.weekNum}</h1> | ||
55 | + <h3>7일</h3> | ||
56 | + </Paper> | ||
57 | + </Grid> | ||
58 | + <Grid item xs={4}> | ||
59 | + <Paper className={classes.paper}> | ||
60 | + <h1>{PSdata.monthNum}</h1> | ||
61 | + <h3>30일</h3> | ||
62 | + </Paper> | ||
63 | + </Grid> | ||
64 | + <Grid item xs={4}> | ||
65 | + <Paper className={classes.paper}> | ||
66 | + <h1>{PSdata.totalNum}</h1> | ||
67 | + <h3>전체</h3> | ||
68 | + </Paper> | ||
69 | + </Grid> | ||
70 | + </Grid> | ||
71 | + </div> | ||
72 | + ) : ( | ||
73 | + <div className={classes.root}> | ||
74 | + <Grid container spacing={5}> | ||
75 | + <Grid item xs={12}> | ||
76 | + <Paper className={classes.paper}> | ||
77 | + <h1></h1> | ||
78 | + <h3>오늘의 추천 문제</h3> | ||
79 | + </Paper> | ||
27 | </Grid> | 80 | </Grid> |
28 | <Grid item xs={6}> | 81 | <Grid item xs={6}> |
29 | - <Paper className={classes.paper}>xs=6</Paper> | 82 | + <Paper className={classes.paper}> |
83 | + <h1></h1> | ||
84 | + <h3>오늘</h3> | ||
85 | + </Paper> | ||
30 | </Grid> | 86 | </Grid> |
31 | - <Grid item xs={3}> | 87 | + <Grid item xs={6}> |
32 | - <Paper className={classes.paper}>xs=3</Paper> | 88 | + <Paper className={classes.paper}> |
89 | + <h1></h1> | ||
90 | + <h3>마지막 날</h3> | ||
91 | + </Paper> | ||
33 | </Grid> | 92 | </Grid> |
34 | - <Grid item xs={3}> | 93 | + |
35 | - <Paper className={classes.paper}>xs=3</Paper> | 94 | + <Grid item xs={4}> |
95 | + <Paper className={classes.paper}> | ||
96 | + <h1></h1> | ||
97 | + <h3>7일</h3> | ||
98 | + </Paper> | ||
36 | </Grid> | 99 | </Grid> |
37 | - <Grid item xs={3}> | 100 | + <Grid item xs={4}> |
38 | - <Paper className={classes.paper}>xs=3</Paper> | 101 | + <Paper className={classes.paper}> |
102 | + <h1></h1> | ||
103 | + <h3>30일</h3> | ||
104 | + </Paper> | ||
39 | </Grid> | 105 | </Grid> |
40 | - <Grid item xs={3}> | 106 | + <Grid item xs={4}> |
41 | - <Paper className={classes.paper}>xs=3</Paper> | 107 | + <Paper className={classes.paper}> |
108 | + <h1></h1> | ||
109 | + <h3>전체</h3> | ||
110 | + </Paper> | ||
42 | </Grid> | 111 | </Grid> |
43 | </Grid> | 112 | </Grid> |
44 | </div> | 113 | </div> | ... | ... |
... | @@ -9,13 +9,16 @@ const useStyles = makeStyles((theme) => ({ | ... | @@ -9,13 +9,16 @@ const useStyles = makeStyles((theme) => ({ |
9 | margin: theme.spacing(1), | 9 | margin: theme.spacing(1), |
10 | }, | 10 | }, |
11 | }, | 11 | }, |
12 | + button: { | ||
13 | + margin: theme.spacing(1), | ||
14 | + }, | ||
12 | })); | 15 | })); |
13 | 16 | ||
14 | const BJIDForm = ({ onChange, onBJIDSubmit, profile, onSyncBJIDSubmit }) => { | 17 | const BJIDForm = ({ onChange, onBJIDSubmit, profile, onSyncBJIDSubmit }) => { |
15 | const classes = useStyles(); | 18 | const classes = useStyles(); |
16 | return ( | 19 | return ( |
17 | <div> | 20 | <div> |
18 | - <form onSubmit={onBJIDSubmit}> | 21 | + <form> |
19 | <TextField | 22 | <TextField |
20 | name="userBJID" | 23 | name="userBJID" |
21 | onChange={onChange} | 24 | onChange={onChange} |
... | @@ -23,11 +26,21 @@ const BJIDForm = ({ onChange, onBJIDSubmit, profile, onSyncBJIDSubmit }) => { | ... | @@ -23,11 +26,21 @@ const BJIDForm = ({ onChange, onBJIDSubmit, profile, onSyncBJIDSubmit }) => { |
23 | placeholder="백준 아이디" | 26 | placeholder="백준 아이디" |
24 | label="백준 아이디" | 27 | label="백준 아이디" |
25 | /> | 28 | /> |
26 | - <Button variant="outlined" type="submit"> | 29 | + </form> |
30 | + <Button | ||
31 | + className={classes.button} | ||
32 | + variant="outlined" | ||
33 | + onClick={onBJIDSubmit} | ||
34 | + color="primary" | ||
35 | + > | ||
27 | 등록 | 36 | 등록 |
28 | </Button> | 37 | </Button> |
29 | - </form> | 38 | + <Button |
30 | - <Button variant="outlined" onClick={onSyncBJIDSubmit}> | 39 | + className={classes.button} |
40 | + variant="outlined" | ||
41 | + onClick={onSyncBJIDSubmit} | ||
42 | + color="secondary" | ||
43 | + > | ||
31 | 동기화 | 44 | 동기화 |
32 | </Button> | 45 | </Button> |
33 | </div> | 46 | </div> | ... | ... |
1 | +import React from 'react'; | ||
2 | +import { makeStyles } from '@material-ui/core/styles'; | ||
3 | + | ||
4 | +import Button from '@material-ui/core/Button'; | ||
5 | +import TextField from '@material-ui/core/TextField'; | ||
6 | + | ||
7 | +const useStyles = makeStyles((theme) => ({ | ||
8 | + root: { | ||
9 | + '& > *': { | ||
10 | + margin: theme.spacing(1), | ||
11 | + }, | ||
12 | + }, | ||
13 | + button: { | ||
14 | + margin: theme.spacing(1), | ||
15 | + }, | ||
16 | +})); | ||
17 | + | ||
18 | +const GoalNumForm = ({ onChange, profile, onGoalNumSubmit }) => { | ||
19 | + const classes = useStyles(); | ||
20 | + return ( | ||
21 | + <div> | ||
22 | + <form> | ||
23 | + <TextField | ||
24 | + name="goalNum" | ||
25 | + type="number" | ||
26 | + onChange={onChange} | ||
27 | + value={profile.goalNum} | ||
28 | + placeholder="일일 목표" | ||
29 | + label="일일 목표" | ||
30 | + InputLabelProps={{ | ||
31 | + shrink: true, | ||
32 | + }} | ||
33 | + /> | ||
34 | + </form> | ||
35 | + <Button | ||
36 | + className={classes.button} | ||
37 | + onClick={onGoalNumSubmit} | ||
38 | + color="primary" | ||
39 | + variant="outlined" | ||
40 | + > | ||
41 | + 등록 | ||
42 | + </Button> | ||
43 | + </div> | ||
44 | + ); | ||
45 | +}; | ||
46 | + | ||
47 | +export default GoalNumForm; |
... | @@ -2,40 +2,54 @@ import React from 'react'; | ... | @@ -2,40 +2,54 @@ import React from 'react'; |
2 | import palette from '../../lib/styles/palette'; | 2 | import palette from '../../lib/styles/palette'; |
3 | import BJIDForm from './BJIDForm'; | 3 | import BJIDForm from './BJIDForm'; |
4 | import SlackForm from './SlackForm'; | 4 | import SlackForm from './SlackForm'; |
5 | +import GoalNumForm from './GoalNumForm'; | ||
5 | import { makeStyles } from '@material-ui/core/styles'; | 6 | import { makeStyles } from '@material-ui/core/styles'; |
6 | import Paper from '@material-ui/core/Paper'; | 7 | import Paper from '@material-ui/core/Paper'; |
7 | import Grid from '@material-ui/core/Grid'; | 8 | import Grid from '@material-ui/core/Grid'; |
9 | +import CircularProgress from '@material-ui/core/CircularProgress'; | ||
10 | +import styled from 'styled-components'; | ||
8 | 11 | ||
9 | const useStyles = makeStyles((theme) => ({ | 12 | const useStyles = makeStyles((theme) => ({ |
10 | root: { | 13 | root: { |
11 | flexGrow: 1, | 14 | flexGrow: 1, |
12 | background: palette.gray[2], | 15 | background: palette.gray[2], |
16 | + padding: theme.spacing(8), | ||
13 | }, | 17 | }, |
14 | paper: { | 18 | paper: { |
19 | + padding: theme.spacing(8), | ||
15 | margin: 'auto', | 20 | margin: 'auto', |
16 | textAlign: 'center', | 21 | textAlign: 'center', |
17 | - padding: 30, | ||
18 | }, | 22 | }, |
19 | })); | 23 | })); |
20 | 24 | ||
25 | +const LoadingParentStyle = styled.div` | ||
26 | + display: flex; | ||
27 | + flex-direction: column; | ||
28 | + justify-content: center; | ||
29 | + align-items: center; | ||
30 | + padding-top: 20px; | ||
31 | +`; | ||
32 | + | ||
21 | const SettingForm = ({ | 33 | const SettingForm = ({ |
22 | onChange, | 34 | onChange, |
23 | onBJIDSubmit, | 35 | onBJIDSubmit, |
24 | onSlackURLSubmit, | 36 | onSlackURLSubmit, |
25 | profile, | 37 | profile, |
26 | onSyncBJIDSubmit, | 38 | onSyncBJIDSubmit, |
39 | + onGoalNumSubmit, | ||
40 | + isLoading, | ||
27 | }) => { | 41 | }) => { |
28 | const classes = useStyles(); | 42 | const classes = useStyles(); |
29 | - return ( | 43 | + return isLoading ? ( |
44 | + <LoadingParentStyle> | ||
45 | + <CircularProgress className={classes.loading} /> | ||
46 | + </LoadingParentStyle> | ||
47 | + ) : ( | ||
30 | <div className={classes.root}> | 48 | <div className={classes.root}> |
31 | - <Grid container spacing={3}> | 49 | + <Grid container spacing={5}> |
32 | - <Grid item xs={12}> | 50 | + <Grid container item xs={6}> |
33 | - <Paper className={classes.paper}> | ||
34 | - <h3>{profile.username}</h3> | ||
35 | - </Paper> | ||
36 | - </Grid> | ||
37 | - <Grid container item xs={12}> | ||
38 | <Paper className={classes.paper} elevation={3}> | 51 | <Paper className={classes.paper} elevation={3}> |
52 | + <h1>백준 아이디</h1> | ||
39 | <BJIDForm | 53 | <BJIDForm |
40 | profile={profile} | 54 | profile={profile} |
41 | onChange={onChange} | 55 | onChange={onChange} |
... | @@ -45,8 +59,9 @@ const SettingForm = ({ | ... | @@ -45,8 +59,9 @@ const SettingForm = ({ |
45 | </Paper> | 59 | </Paper> |
46 | </Grid> | 60 | </Grid> |
47 | 61 | ||
48 | - <Grid container item xs={12}> | 62 | + <Grid container item xs={6}> |
49 | <Paper className={classes.paper} elevation={3}> | 63 | <Paper className={classes.paper} elevation={3}> |
64 | + <h1>슬랙 Hook URL</h1> | ||
50 | <SlackForm | 65 | <SlackForm |
51 | profile={profile} | 66 | profile={profile} |
52 | onChange={onChange} | 67 | onChange={onChange} |
... | @@ -54,6 +69,17 @@ const SettingForm = ({ | ... | @@ -54,6 +69,17 @@ const SettingForm = ({ |
54 | /> | 69 | /> |
55 | </Paper> | 70 | </Paper> |
56 | </Grid> | 71 | </Grid> |
72 | + | ||
73 | + <Grid container item xs={6}> | ||
74 | + <Paper className={classes.paper} elevation={3}> | ||
75 | + <h1>일일 목표</h1> | ||
76 | + <GoalNumForm | ||
77 | + profile={profile} | ||
78 | + onChange={onChange} | ||
79 | + onGoalNumSubmit={onGoalNumSubmit} | ||
80 | + /> | ||
81 | + </Paper> | ||
82 | + </Grid> | ||
57 | </Grid> | 83 | </Grid> |
58 | </div> | 84 | </div> |
59 | ); | 85 | ); | ... | ... |
... | @@ -10,13 +10,16 @@ const useStyles = makeStyles((theme) => ({ | ... | @@ -10,13 +10,16 @@ const useStyles = makeStyles((theme) => ({ |
10 | margin: theme.spacing(1), | 10 | margin: theme.spacing(1), |
11 | }, | 11 | }, |
12 | }, | 12 | }, |
13 | + button: { | ||
14 | + margin: theme.spacing(1), | ||
15 | + }, | ||
13 | })); | 16 | })); |
14 | 17 | ||
15 | const SlackForm = ({ onChange, profile, onSlackURLSubmit }) => { | 18 | const SlackForm = ({ onChange, profile, onSlackURLSubmit }) => { |
16 | const classes = useStyles(); | 19 | const classes = useStyles(); |
17 | return ( | 20 | return ( |
18 | <div> | 21 | <div> |
19 | - <form onSubmit={onSlackURLSubmit}> | 22 | + <form> |
20 | <TextField | 23 | <TextField |
21 | name="slackWebHookURL" | 24 | name="slackWebHookURL" |
22 | onChange={onChange} | 25 | onChange={onChange} |
... | @@ -24,10 +27,16 @@ const SlackForm = ({ onChange, profile, onSlackURLSubmit }) => { | ... | @@ -24,10 +27,16 @@ const SlackForm = ({ onChange, profile, onSlackURLSubmit }) => { |
24 | placeholder="슬랙 Webhook URL" | 27 | placeholder="슬랙 Webhook URL" |
25 | label="슬랙 Webhook URL" | 28 | label="슬랙 Webhook URL" |
26 | /> | 29 | /> |
27 | - <Button variant="outlined" type="submit"> | 30 | + </form> |
31 | + <Button | ||
32 | + className={classes.button} | ||
33 | + onClick={onSlackURLSubmit} | ||
34 | + variant="outlined" | ||
35 | + type="submit" | ||
36 | + color="primary" | ||
37 | + > | ||
28 | 등록 | 38 | 등록 |
29 | </Button> | 39 | </Button> |
30 | - </form> | ||
31 | </div> | 40 | </div> |
32 | ); | 41 | ); |
33 | }; | 42 | }; | ... | ... |
... | @@ -2,21 +2,35 @@ import React, { useEffect } from 'react'; | ... | @@ -2,21 +2,35 @@ import React, { useEffect } from 'react'; |
2 | import { useDispatch, useSelector } from 'react-redux'; | 2 | import { useDispatch, useSelector } from 'react-redux'; |
3 | import { withRouter } from 'react-router-dom'; | 3 | import { withRouter } from 'react-router-dom'; |
4 | import HomeForm from '../../components/home/HomeForm'; | 4 | import HomeForm from '../../components/home/HomeForm'; |
5 | -import { getPROFILE } from '../../modules/profile'; | 5 | +import { getPROFILE, initializeProfile } from '../../modules/profile'; |
6 | -import { analyzeBJ } from '../../lib/util/analyzeBJ'; | ||
7 | const HomeContainer = ({ history }) => { | 6 | const HomeContainer = ({ history }) => { |
8 | const dispatch = useDispatch(); | 7 | const dispatch = useDispatch(); |
9 | const { user, profile } = useSelector(({ user, profile }) => ({ | 8 | const { user, profile } = useSelector(({ user, profile }) => ({ |
10 | user: user.user, | 9 | user: user.user, |
11 | profile: profile, | 10 | profile: profile, |
12 | })); | 11 | })); |
13 | - useEffect(() => {}, [profile.solvedBJ]); | 12 | + |
13 | + useEffect(() => { | ||
14 | + if (!user) { | ||
15 | + alert('로그인이 필요합니다 '); | ||
16 | + history.push('/login'); | ||
17 | + } else { | ||
18 | + let username = user.username; | ||
19 | + dispatch(getPROFILE({ username })); | ||
20 | + return () => { | ||
21 | + dispatch(initializeProfile()); | ||
22 | + }; | ||
23 | + } | ||
24 | + }, [dispatch, user, history]); | ||
25 | + useEffect(() => { | ||
26 | + console.log(profile); | ||
27 | + }, [profile]); | ||
14 | useEffect(() => { | 28 | useEffect(() => { |
15 | if (user) { | 29 | if (user) { |
16 | let username = user.username; | 30 | let username = user.username; |
17 | dispatch(getPROFILE({ username })); | 31 | dispatch(getPROFILE({ username })); |
18 | } | 32 | } |
19 | }, [dispatch, user]); | 33 | }, [dispatch, user]); |
20 | - return <HomeForm />; | 34 | + return <HomeForm PSdata={profile.solvedBJ_date} goalNum={profile.goalNum} />; |
21 | }; | 35 | }; |
22 | export default withRouter(HomeContainer); | 36 | export default withRouter(HomeContainer); | ... | ... |
1 | -import React, { useEffect } from 'react'; | 1 | +import React, { useEffect, useState } from 'react'; |
2 | import { useDispatch, useSelector } from 'react-redux'; | 2 | import { useDispatch, useSelector } from 'react-redux'; |
3 | + | ||
3 | import { withRouter } from 'react-router-dom'; | 4 | import { withRouter } from 'react-router-dom'; |
4 | import { | 5 | import { |
5 | changeField, | 6 | changeField, |
... | @@ -8,15 +9,21 @@ import { | ... | @@ -8,15 +9,21 @@ import { |
8 | syncBJID, | 9 | syncBJID, |
9 | initializeProfile, | 10 | initializeProfile, |
10 | setSLACK, | 11 | setSLACK, |
12 | + setGOALNUM, | ||
11 | } from '../../modules/profile'; | 13 | } from '../../modules/profile'; |
12 | import SettingForm from '../../components/setting/SettingForm'; | 14 | import SettingForm from '../../components/setting/SettingForm'; |
13 | 15 | ||
14 | const SettingContainer = ({ history }) => { | 16 | const SettingContainer = ({ history }) => { |
17 | + const [isLoading, setLoading] = useState(false); | ||
18 | + | ||
15 | const dispatch = useDispatch(); | 19 | const dispatch = useDispatch(); |
16 | - const { user, profile } = useSelector(({ user, profile }) => ({ | 20 | + const { user, profile, loading } = useSelector( |
21 | + ({ user, profile, loading }) => ({ | ||
17 | user: user.user, | 22 | user: user.user, |
18 | profile: profile, | 23 | profile: profile, |
19 | - })); | 24 | + loading: loading, |
25 | + }), | ||
26 | + ); | ||
20 | 27 | ||
21 | const onChange = (e) => { | 28 | const onChange = (e) => { |
22 | const { value, name } = e.target; | 29 | const { value, name } = e.target; |
... | @@ -33,6 +40,13 @@ const SettingContainer = ({ history }) => { | ... | @@ -33,6 +40,13 @@ const SettingContainer = ({ history }) => { |
33 | let username = profile.username; | 40 | let username = profile.username; |
34 | dispatch(syncBJID({ username })); | 41 | dispatch(syncBJID({ username })); |
35 | }; | 42 | }; |
43 | + | ||
44 | + const onGoalNumSubmit = (e) => { | ||
45 | + e.preventDefault(); | ||
46 | + let username = profile.username; | ||
47 | + let goalNum = profile.goalNum; | ||
48 | + dispatch(setGOALNUM({ username, goalNum })); | ||
49 | + }; | ||
36 | const onSlackURLSubmit = (e) => { | 50 | const onSlackURLSubmit = (e) => { |
37 | e.preventDefault(); | 51 | e.preventDefault(); |
38 | let username = profile.username; | 52 | let username = profile.username; |
... | @@ -51,7 +65,7 @@ const SettingContainer = ({ history }) => { | ... | @@ -51,7 +65,7 @@ const SettingContainer = ({ history }) => { |
51 | useEffect(() => { | 65 | useEffect(() => { |
52 | if (!user) { | 66 | if (!user) { |
53 | alert('로그인이 필요합니다 '); | 67 | alert('로그인이 필요합니다 '); |
54 | - history.push('/'); | 68 | + history.push('/login'); |
55 | } else { | 69 | } else { |
56 | let username = user.username; | 70 | let username = user.username; |
57 | dispatch(getPROFILE({ username })); | 71 | dispatch(getPROFILE({ username })); |
... | @@ -60,16 +74,27 @@ const SettingContainer = ({ history }) => { | ... | @@ -60,16 +74,27 @@ const SettingContainer = ({ history }) => { |
60 | }; | 74 | }; |
61 | } | 75 | } |
62 | }, [dispatch, user, history]); | 76 | }, [dispatch, user, history]); |
77 | + useEffect(() => { | ||
78 | + if (loading['profile/SYNC_BJID'] == true) { | ||
79 | + setLoading(true); | ||
80 | + } else { | ||
81 | + setLoading(false); | ||
82 | + } | ||
83 | + }, [dispatch, loading]); | ||
63 | 84 | ||
64 | return ( | 85 | return ( |
86 | + <div> | ||
65 | <SettingForm | 87 | <SettingForm |
66 | type="setting" | 88 | type="setting" |
67 | onChange={onChange} | 89 | onChange={onChange} |
68 | onBJIDSubmit={onBJIDSubmit} | 90 | onBJIDSubmit={onBJIDSubmit} |
69 | onSyncBJIDSubmit={onSyncBJIDSubmit} | 91 | onSyncBJIDSubmit={onSyncBJIDSubmit} |
70 | onSlackURLSubmit={onSlackURLSubmit} | 92 | onSlackURLSubmit={onSlackURLSubmit} |
93 | + onGoalNumSubmit={onGoalNumSubmit} | ||
71 | profile={profile} | 94 | profile={profile} |
95 | + isLoading={isLoading} | ||
72 | ></SettingForm> | 96 | ></SettingForm> |
97 | + </div> | ||
73 | ); | 98 | ); |
74 | }; | 99 | }; |
75 | 100 | ... | ... |
... | @@ -17,6 +17,11 @@ const [ | ... | @@ -17,6 +17,11 @@ const [ |
17 | SET_SLACK_FAILURE, | 17 | SET_SLACK_FAILURE, |
18 | ] = createRequestActionTypes('/profile/SET_SLACK'); | 18 | ] = createRequestActionTypes('/profile/SET_SLACK'); |
19 | const [ | 19 | const [ |
20 | + SET_GOALNUM, | ||
21 | + SET_GOALNUM_SUCCESS, | ||
22 | + SET_GOALNUM_FAILURE, | ||
23 | +] = createRequestActionTypes('/profile/SET_GOALNUM'); | ||
24 | +const [ | ||
20 | GET_PROFILE, | 25 | GET_PROFILE, |
21 | GET_PROFILE_SUCCESS, | 26 | GET_PROFILE_SUCCESS, |
22 | GET_PROFILE_FAILURE, | 27 | GET_PROFILE_FAILURE, |
... | @@ -31,6 +36,7 @@ export const initializeProfile = createAction(INITIALIZE); | ... | @@ -31,6 +36,7 @@ export const initializeProfile = createAction(INITIALIZE); |
31 | export const syncBJID = createAction(SYNC_BJID, ({ username }) => ({ | 36 | export const syncBJID = createAction(SYNC_BJID, ({ username }) => ({ |
32 | username, | 37 | username, |
33 | })); | 38 | })); |
39 | + | ||
34 | export const setSLACK = createAction( | 40 | export const setSLACK = createAction( |
35 | SET_SLACK, | 41 | SET_SLACK, |
36 | ({ username, slackWebHookURL }) => ({ | 42 | ({ username, slackWebHookURL }) => ({ |
... | @@ -38,6 +44,14 @@ export const setSLACK = createAction( | ... | @@ -38,6 +44,14 @@ export const setSLACK = createAction( |
38 | slackWebHookURL, | 44 | slackWebHookURL, |
39 | }), | 45 | }), |
40 | ); | 46 | ); |
47 | + | ||
48 | +export const setGOALNUM = createAction( | ||
49 | + SET_GOALNUM, | ||
50 | + ({ username, goalNum }) => ({ | ||
51 | + username, | ||
52 | + goalNum, | ||
53 | + }), | ||
54 | +); | ||
41 | export const setBJID = createAction(SET_BJID, ({ username, userBJID }) => ({ | 55 | export const setBJID = createAction(SET_BJID, ({ username, userBJID }) => ({ |
42 | username, | 56 | username, |
43 | userBJID, | 57 | userBJID, |
... | @@ -58,16 +72,21 @@ const initialState = { | ... | @@ -58,16 +72,21 @@ const initialState = { |
58 | friendList: [], | 72 | friendList: [], |
59 | profileError: '', | 73 | profileError: '', |
60 | slackWebHookURL: '', | 74 | slackWebHookURL: '', |
75 | + solvedBJ_date: '', | ||
76 | + goalNum: '', | ||
61 | }; | 77 | }; |
62 | const getPROFILESaga = createRequestSaga(GET_PROFILE, profileAPI.getPROFILE); | 78 | const getPROFILESaga = createRequestSaga(GET_PROFILE, profileAPI.getPROFILE); |
63 | const setBJIDSaga = createRequestSaga(SET_BJID, profileAPI.setBJID); | 79 | const setBJIDSaga = createRequestSaga(SET_BJID, profileAPI.setBJID); |
64 | const setSLACKSaga = createRequestSaga(SET_SLACK, profileAPI.setPROFILE); | 80 | const setSLACKSaga = createRequestSaga(SET_SLACK, profileAPI.setPROFILE); |
81 | +const setGOALNUMSaga = createRequestSaga(SET_GOALNUM, profileAPI.setPROFILE); | ||
65 | const syncBJIDSaga = createRequestSaga(SYNC_BJID, profileAPI.syncBJ); | 82 | const syncBJIDSaga = createRequestSaga(SYNC_BJID, profileAPI.syncBJ); |
83 | + | ||
66 | export function* profileSaga() { | 84 | export function* profileSaga() { |
67 | yield takeLatest(SET_BJID, setBJIDSaga); | 85 | yield takeLatest(SET_BJID, setBJIDSaga); |
68 | yield takeLatest(GET_PROFILE, getPROFILESaga); | 86 | yield takeLatest(GET_PROFILE, getPROFILESaga); |
69 | yield takeLatest(SYNC_BJID, syncBJIDSaga); | 87 | yield takeLatest(SYNC_BJID, syncBJIDSaga); |
70 | yield takeLatest(SET_SLACK, setSLACKSaga); | 88 | yield takeLatest(SET_SLACK, setSLACKSaga); |
89 | + yield takeLatest(SET_GOALNUM, setGOALNUMSaga); | ||
71 | } | 90 | } |
72 | 91 | ||
73 | export default handleActions( | 92 | export default handleActions( |
... | @@ -80,7 +99,15 @@ export default handleActions( | ... | @@ -80,7 +99,15 @@ export default handleActions( |
80 | [GET_PROFILE_SUCCESS]: ( | 99 | [GET_PROFILE_SUCCESS]: ( |
81 | state, | 100 | state, |
82 | { | 101 | { |
83 | - payload: { username, userBJID, solvedBJ, friendList, slackWebHookURL }, | 102 | + payload: { |
103 | + username, | ||
104 | + userBJID, | ||
105 | + solvedBJ, | ||
106 | + friendList, | ||
107 | + slackWebHookURL, | ||
108 | + solvedBJ_date, | ||
109 | + goalNum, | ||
110 | + }, | ||
84 | }, | 111 | }, |
85 | ) => ({ | 112 | ) => ({ |
86 | ...state, | 113 | ...state, |
... | @@ -90,6 +117,8 @@ export default handleActions( | ... | @@ -90,6 +117,8 @@ export default handleActions( |
90 | friendList: friendList, | 117 | friendList: friendList, |
91 | profileError: null, | 118 | profileError: null, |
92 | slackWebHookURL: slackWebHookURL, | 119 | slackWebHookURL: slackWebHookURL, |
120 | + solvedBJ_date: solvedBJ_date, | ||
121 | + goalNum: goalNum, | ||
93 | }), | 122 | }), |
94 | [GET_PROFILE_FAILURE]: (state, { payload: error }) => ({ | 123 | [GET_PROFILE_FAILURE]: (state, { payload: error }) => ({ |
95 | ...state, | 124 | ...state, |
... | @@ -114,6 +143,14 @@ export default handleActions( | ... | @@ -114,6 +143,14 @@ export default handleActions( |
114 | ...state, | 143 | ...state, |
115 | profileError: error, | 144 | profileError: error, |
116 | }), | 145 | }), |
146 | + [SET_GOALNUM_SUCCESS]: (state, { payload: { goalNum } }) => ({ | ||
147 | + ...state, | ||
148 | + goalNum: goalNum, | ||
149 | + }), | ||
150 | + [SET_GOALNUM_FAILURE]: (state, { payload: error }) => ({ | ||
151 | + ...state, | ||
152 | + profileError: error, | ||
153 | + }), | ||
117 | [SYNC_BJID_SUCCESS]: (state, { payload: { solvedBJ } }) => ({ | 154 | [SYNC_BJID_SUCCESS]: (state, { payload: { solvedBJ } }) => ({ |
118 | ...state, | 155 | ...state, |
119 | solvedBJ, | 156 | solvedBJ, | ... | ... |
jaksimsamil-server/API.md
deleted
100644 → 0
1 | -# Jaksimsamil API Documentation | ||
2 | - | ||
3 | -## Overview | ||
4 | - | ||
5 | -- TBA | ||
6 | - | ||
7 | -## URL | ||
8 | - | ||
9 | -- TBA | ||
10 | - | ||
11 | -## Usage | ||
12 | - | ||
13 | -- TBA | ||
14 | - | ||
15 | -## Example | ||
16 | - | ||
17 | -- TBA | ||
18 | - | ||
19 | -## API Table | ||
20 | - | ||
21 | -| group | description | method | URL | Detail | Auth | | ||
22 | -| ------- | --------------------------- | --------- | ------------------------ | -------- | --------- | | ||
23 | -| user | 유저 등록 | POST | api/user | 바로가기 | JWT Token | | ||
24 | -| user | 유저 삭제 | DELETE | api/user:id | 바로가기 | JWT Token | | ||
25 | -| user | 특정 유저 조회 | GET | api/user:id | 바로가기 | None | | ||
26 | -| user | 전체 유저 조회 | GET | api/user | 바로가기 | JWT Token | | ||
27 | -| friend | 유저 친구 등록 | POST | api/friend | 바로가기 | JWT Token | | ||
28 | -| friend | 유저의 친구 조회 | GET | api/friend:id | 바로가기 | None | | ||
29 | -| profile | 유저가 푼 문제 조회(백준) | GET | api/profile/solvedBJ:id | 바로가기 | None | | ||
30 | -| profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | 바로가기 | None | | ||
31 | -| profile | 유저 정보 수정 | POST | api/profile/setprofile | 바로가기 | JWT TOKEN | | ||
32 | -| profile | 유저 정보 받아오기 | POST | api/profile/getprofile | 바로가기 | JWT | | ||
33 | -| profile | 추천 문제 조회 | GET | api/profile/recommend:id | 바로가기 | None | | ||
34 | -| notify | 슬랙 메시지 전송 요청 | POST | api/notify/ | | ||
35 | -| slack | 바로가기 | Jwt Token | | ||
36 | -| auth | 로그인 | POST | api/auth/login | 바로가기 | None | | ||
37 | -| auth | 로그아웃 | POST | api/auth/logout | 바로가기 | JWT Token | | ||
38 | -| auth | 회원가입 | POST | api/auth/register | 바로가기 | None | | ||
39 | -| auth | 로그인 확인 | GET | api/auth/check | 바로가기 | None | |
jaksimsamil-server/README.md
0 → 100644
1 | +# Jaksimsamil Server Documentation | ||
2 | + | ||
3 | +## Overview | ||
4 | + | ||
5 | +- KOA 프레임워크 기반의 REST-API로 동작합니다. | ||
6 | +- API 문서는 아래를 참고해주세요. | ||
7 | + | ||
8 | +## Usage | ||
9 | + | ||
10 | +- Starting Server | ||
11 | + | ||
12 | +``` | ||
13 | +npm install | ||
14 | +npm update | ||
15 | +node index.js | ||
16 | +``` | ||
17 | + | ||
18 | +## Example | ||
19 | + | ||
20 | +``` | ||
21 | +POST http://facerain.dcom.club/profile/getprofile | ||
22 | +{ | ||
23 | + username: 'syw5141', | ||
24 | +} | ||
25 | +``` | ||
26 | + | ||
27 | +## API Table | ||
28 | + | ||
29 | +| group | description | method | URL | Detail | Auth | | ||
30 | +| ------- | -------------------------------------- | ------ | ----------------------- | -------------------------------------- | --------- | | ||
31 | +| profile | 유저가 푼 문제 조회(백준) | GET | api/profile/solvedBJ:id | [바로가기](/src/api/profile/README.md) | None | | ||
32 | +| profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | [바로가기](/src/api/profile/README.md) | None | | ||
33 | +| profile | 유저 정보 수정 | POST | api/profile/setprofile | [바로가기](/src/api/profile/README.md) | JWT TOKEN | | ||
34 | +| profile | 유저 정보 받아오기 | POST | api/profile/getprofile | [바로가기](/src/api/profile/README.md) | JWT | | ||
35 | +| profile | 추천 문제 조회 | POST | api/profile/recommend | [바로가기](/src/api/profile/README.md) | None | | ||
36 | +| profile | 친구 추가 | POST | /api/profile/addfriend | [바로가기](/src/api/profile/README.md) | JWT TOKEN | | ||
37 | +| notify | 슬랙 메시지 전송 요청 (목표 성취 여부) | POST | api/notify/goal | [바로가기](/src/api/notify/README.md) | Jwt Token | | ||
38 | +| notify | 슬랙 메시지 전송 요청 (문제 추천) | POST | api/notify/recommend | [바로가기](/src/api/notify/README.md) | None | | ||
39 | +| auth | 로그인 | POST | api/auth/login | [바로가기](/src/api/auth/README.md) | None | | ||
40 | +| auth | 로그아웃 | POST | api/auth/logout | [바로가기](/src/api/auth/README.md) | JWT Token | | ||
41 | +| auth | 회원가입 | POST | api/auth/register | [바로가기](/src/api/auth/README.md) | None | | ||
42 | +| auth | 로그인 확인 | GET | api/auth/check | [바로가기](/src/api/auth/README.md) | None | |
jaksimsamil-server/access.log
deleted
100644 → 0
This diff could not be displayed because it is too large.
jaksimsamil-server/npm-debug.log
0 → 100644
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
5 | "license": "MIT", | 5 | "license": "MIT", |
6 | "dependencies": { | 6 | "dependencies": { |
7 | "axios": "^0.19.2", | 7 | "axios": "^0.19.2", |
8 | - "bcrypt": "^4.0.1", | 8 | + "bcrypt": "^3.0.0", |
9 | "body-parser": "^1.19.0", | 9 | "body-parser": "^1.19.0", |
10 | "cheerio": "^1.0.0-rc.3", | 10 | "cheerio": "^1.0.0-rc.3", |
11 | "cookie-parser": "^1.4.5", | 11 | "cookie-parser": "^1.4.5", |
... | @@ -15,11 +15,11 @@ | ... | @@ -15,11 +15,11 @@ |
15 | "iconv": "^3.0.0", | 15 | "iconv": "^3.0.0", |
16 | "joi": "^14.3.1", | 16 | "joi": "^14.3.1", |
17 | "jsonwebtoken": "^8.5.1", | 17 | "jsonwebtoken": "^8.5.1", |
18 | - "koa": "^2.12.0", | 18 | + "koa": "^2.13.0", |
19 | "koa-bodyparser": "^4.3.0", | 19 | "koa-bodyparser": "^4.3.0", |
20 | "koa-morgan": "^1.0.1", | 20 | "koa-morgan": "^1.0.1", |
21 | "koa-router": "^9.0.1", | 21 | "koa-router": "^9.0.1", |
22 | - "mongoose": "^5.9.17", | 22 | + "mongoose": "^5.9.20", |
23 | "morgan": "^1.10.0", | 23 | "morgan": "^1.10.0", |
24 | "node-schedule": "^1.3.2", | 24 | "node-schedule": "^1.3.2", |
25 | "path": "^0.12.7", | 25 | "path": "^0.12.7", |
... | @@ -29,11 +29,11 @@ | ... | @@ -29,11 +29,11 @@ |
29 | }, | 29 | }, |
30 | "devDependencies": { | 30 | "devDependencies": { |
31 | "babel-eslint": "^10.1.0", | 31 | "babel-eslint": "^10.1.0", |
32 | - "eslint": "^7.1.0", | 32 | + "eslint": "^7.3.1", |
33 | "nodemon": "^2.0.4" | 33 | "nodemon": "^2.0.4" |
34 | }, | 34 | }, |
35 | "scripts": { | 35 | "scripts": { |
36 | - "start": "node src", | 36 | + "start": "node ./index.js", |
37 | "start:dev": "nodemon --watch src/ src/index.js" | 37 | "start:dev": "nodemon --watch src/ src/index.js" |
38 | } | 38 | } |
39 | } | 39 | } | ... | ... |
jaksimsamil-server/src/api/auth/README.md
0 → 100644
File mode changed
jaksimsamil-server/src/api/friend/README.md
0 → 100644
File mode changed
... | @@ -3,7 +3,7 @@ const api = new Router(); | ... | @@ -3,7 +3,7 @@ const api = new Router(); |
3 | 3 | ||
4 | const auth = require("./auth"); | 4 | const auth = require("./auth"); |
5 | const friend = require("./friend"); | 5 | const friend = require("./friend"); |
6 | -const notify = require("./profile"); | 6 | +const notify = require("./notify"); |
7 | const user = require("./user"); | 7 | const user = require("./user"); |
8 | const profile = require("./profile"); | 8 | const profile = require("./profile"); |
9 | 9 | ... | ... |
jaksimsamil-server/src/api/notify/README.md
0 → 100644
File mode changed
1 | const Router = require("koa-router"); | 1 | const Router = require("koa-router"); |
2 | const notify = new Router(); | 2 | const notify = new Router(); |
3 | - | 3 | +const slackCtrl = require("./slack.ctrl"); |
4 | -notify.post("/slack"); | 4 | +notify.post("/slack/goal", slackCtrl.slackGoal); |
5 | +notify.post("/slack/recommend", slackCtrl.slackRecommend); | ||
5 | 6 | ||
6 | module.exports = notify; | 7 | module.exports = notify; | ... | ... |
1 | +const Profile = require("../../models/profile"); | ||
2 | +const sendSlack = require("../../util/sendSlack"); | ||
3 | +const problem_set = require("../../data/problem_set"); | ||
4 | +const compareBJ = require("../../util/compareBJ"); | ||
5 | +/* | ||
6 | +POST api/notify/slack/goal | ||
7 | +{ | ||
8 | + username: "username" | ||
9 | +} | ||
10 | +*/ | ||
11 | +exports.slackGoal = async (ctx) => { | ||
12 | + try { | ||
13 | + const { username } = ctx.request.body; | ||
14 | + | ||
15 | + const profile = await Profile.findByUsername(username); | ||
16 | + if (!profile) { | ||
17 | + ctx.status = 401; | ||
18 | + return; | ||
19 | + } | ||
20 | + let slackURL = profile.getslackURL(); | ||
21 | + if (!slackURL) { | ||
22 | + ctx.status = 401; | ||
23 | + return; | ||
24 | + } | ||
25 | + let goalNum = profile.getgoalNum(); | ||
26 | + let todayNum = profile.getTodaySovled(); | ||
27 | + let message = ""; | ||
28 | + if (goalNum < todayNum) { | ||
29 | + message = | ||
30 | + "오늘의 목표 " + | ||
31 | + goalNum + | ||
32 | + "문제 중 " + | ||
33 | + todayNum + | ||
34 | + "문제를 풀었습니다." + | ||
35 | + "\n" + | ||
36 | + "잘하셨습니다!"; | ||
37 | + } else { | ||
38 | + message = | ||
39 | + "오늘의 목표 " + | ||
40 | + goalNum + | ||
41 | + "문제 중 " + | ||
42 | + todayNum + | ||
43 | + "문제를 풀었습니다." + | ||
44 | + "\n" + | ||
45 | + "분발하세요!"; | ||
46 | + } | ||
47 | + | ||
48 | + sendSlack.send(message, slackURL); | ||
49 | + } catch (e) { | ||
50 | + ctx.throw(500, e); | ||
51 | + } | ||
52 | +}; | ||
53 | + | ||
54 | +/* | ||
55 | +POST api/notify/slack/recommend | ||
56 | +{ | ||
57 | + username: "username" | ||
58 | +} | ||
59 | +*/ | ||
60 | +exports.slackRecommend = async (ctx) => { | ||
61 | + try { | ||
62 | + console.log("1"); | ||
63 | + const { username } = ctx.request.body; | ||
64 | + | ||
65 | + const profile = await Profile.findByUsername(username); | ||
66 | + if (!profile) { | ||
67 | + ctx.status = 401; | ||
68 | + return; | ||
69 | + } | ||
70 | + let slackURL = profile.getslackURL(); | ||
71 | + if (!slackURL) { | ||
72 | + ctx.status = 401; | ||
73 | + return; | ||
74 | + } | ||
75 | + let unsolved_data = compareBJ.compareBJ( | ||
76 | + profile.getBJdata(), | ||
77 | + problem_set.problem_set | ||
78 | + ); | ||
79 | + let recommendData = compareBJ.randomItem(unsolved_data); | ||
80 | + | ||
81 | + if (!recommendData) { | ||
82 | + ctx.status = 401; | ||
83 | + return; | ||
84 | + } | ||
85 | + let message = | ||
86 | + "오늘의 추천 문제는 " + | ||
87 | + recommendData.problem_number + | ||
88 | + "번 " + | ||
89 | + " <https://www.boj.kr/" + | ||
90 | + recommendData.problem_number + | ||
91 | + "|" + | ||
92 | + recommendData.problem_title + | ||
93 | + ">" + | ||
94 | + " 입니다."; | ||
95 | + sendSlack.send(message, slackURL); | ||
96 | + } catch (e) { | ||
97 | + ctx.throw(500, e); | ||
98 | + } | ||
99 | +}; |
jaksimsamil-server/src/api/profile/README.md
0 → 100644
1 | +. |
1 | const Router = require("koa-router"); | 1 | const Router = require("koa-router"); |
2 | const profile = new Router(); | 2 | const profile = new Router(); |
3 | const profileCtrl = require("./profile.ctrl"); | 3 | const profileCtrl = require("./profile.ctrl"); |
4 | - | ||
5 | profile.post("/solved:id"); | 4 | profile.post("/solved:id"); |
6 | profile.get("/solvednum:id"); | 5 | profile.get("/solvednum:id"); |
7 | -profile.get("/recommendps:id"); | 6 | +profile.post("/recommend", profileCtrl.recommend); |
8 | profile.patch("/syncBJ", profileCtrl.syncBJ); | 7 | profile.patch("/syncBJ", profileCtrl.syncBJ); |
9 | profile.post("/setprofile", profileCtrl.setProfile); | 8 | profile.post("/setprofile", profileCtrl.setProfile); |
10 | profile.post("/getprofile", profileCtrl.getProfile); | 9 | profile.post("/getprofile", profileCtrl.getProfile); | ... | ... |
... | @@ -2,6 +2,9 @@ const Profile = require("../../models/profile"); | ... | @@ -2,6 +2,9 @@ const Profile = require("../../models/profile"); |
2 | const mongoose = require("mongoose"); | 2 | const mongoose = require("mongoose"); |
3 | const getBJ = require("../../util/getBJ"); | 3 | const getBJ = require("../../util/getBJ"); |
4 | const Joi = require("joi"); | 4 | const Joi = require("joi"); |
5 | +const analyzeBJ = require("../../util/analyzeBJ"); | ||
6 | +const compareBJ = require("../../util/compareBJ"); | ||
7 | +const problem_set = require("../../data/problem_set"); | ||
5 | 8 | ||
6 | const { ObjectId } = mongoose.Types; | 9 | const { ObjectId } = mongoose.Types; |
7 | 10 | ||
... | @@ -47,7 +50,7 @@ exports.setProfile = async (ctx) => { | ... | @@ -47,7 +50,7 @@ exports.setProfile = async (ctx) => { |
47 | //freindList: Joi.array().items(Joi.string()), | 50 | //freindList: Joi.array().items(Joi.string()), |
48 | }) | 51 | }) |
49 | .unknown(); | 52 | .unknown(); |
50 | - | 53 | + console.log(ctx.request.body); |
51 | const result = Joi.validate(ctx.request.body, schema); | 54 | const result = Joi.validate(ctx.request.body, schema); |
52 | if (result.error) { | 55 | if (result.error) { |
53 | ctx.status = 400; | 56 | ctx.status = 400; |
... | @@ -95,9 +98,10 @@ exports.syncBJ = async function (ctx) { | ... | @@ -95,9 +98,10 @@ exports.syncBJ = async function (ctx) { |
95 | } | 98 | } |
96 | const BJID = await profile.getBJID(); | 99 | const BJID = await profile.getBJID(); |
97 | let BJdata = await getBJ.getBJ(BJID); | 100 | let BJdata = await getBJ.getBJ(BJID); |
101 | + let BJdata_date = await analyzeBJ.analyzeBJ(BJdata); | ||
98 | const updateprofile = await Profile.findOneAndUpdate( | 102 | const updateprofile = await Profile.findOneAndUpdate( |
99 | { username: username }, | 103 | { username: username }, |
100 | - { solvedBJ: BJdata }, | 104 | + { solvedBJ: BJdata, solvedBJ_date: BJdata_date }, |
101 | { new: true } | 105 | { new: true } |
102 | ).exec(); | 106 | ).exec(); |
103 | ctx.body = updateprofile; | 107 | ctx.body = updateprofile; |
... | @@ -105,3 +109,33 @@ exports.syncBJ = async function (ctx) { | ... | @@ -105,3 +109,33 @@ exports.syncBJ = async function (ctx) { |
105 | ctx.throw(500, e); | 109 | ctx.throw(500, e); |
106 | } | 110 | } |
107 | }; | 111 | }; |
112 | + | ||
113 | +/* | ||
114 | +POST /api/proflie/recommend | ||
115 | +{ | ||
116 | + username: 'userid' | ||
117 | +} | ||
118 | + */ | ||
119 | +exports.recommend = async (ctx) => { | ||
120 | + const { username } = ctx.request.body; | ||
121 | + | ||
122 | + if (!username) { | ||
123 | + ctx.status = 401; | ||
124 | + return; | ||
125 | + } | ||
126 | + try { | ||
127 | + const profile = await Profile.findByUsername(username); | ||
128 | + if (!profile) { | ||
129 | + ctx.status = 401; | ||
130 | + return; | ||
131 | + } | ||
132 | + let unsolved_data = compareBJ.compareBJ( | ||
133 | + profile.getBJdata(), | ||
134 | + problem_set.problem_set | ||
135 | + ); | ||
136 | + ctx.body = compareBJ.randomItem(unsolved_data); | ||
137 | + //데이터가 비었을 떄 예외처리 필요 | ||
138 | + } catch (e) { | ||
139 | + ctx.throw(500, e); | ||
140 | + } | ||
141 | +}; | ... | ... |
jaksimsamil-server/src/api/user/README.md
0 → 100644
File mode changed
This diff could not be displayed because it is too large.
jaksimsamil-server/src/models/challenge.js
0 → 100644
1 | +const mongoose = require("mongoose"); | ||
2 | + | ||
3 | +const { Schema } = mongoose; | ||
4 | + | ||
5 | +const GroupSchema = new Schema({ | ||
6 | + members: { type: [String] }, | ||
7 | +}); | ||
8 | + | ||
9 | +const ChallengeSchema = new Schema({ | ||
10 | + challengeName: { type: String, required: true }, | ||
11 | + startDate: { type: Object, required: true }, | ||
12 | + endDate: { type: Object, required: true }, | ||
13 | + durationPerSession: { type: String, required: true }, // '1d' means one day per session, '2w' means 2 weeks per session, '3m' means 3 months per session. | ||
14 | + goalPerSession: { type: Number, required: true }, // number of problems for one session | ||
15 | + groups: { type: [GroupSchema], required: true }, // groups attending challenge, group of only one member supposed to be single | ||
16 | +}); | ||
17 | + | ||
18 | +ChallengeSchema.statics.findByChallengeName = function (challengeName) { | ||
19 | + return this.findOne({ challengeName: challengeName }); | ||
20 | +}; | ||
21 | + | ||
22 | +ChallengeSchema.methods.addNewGroup = function (group) { | ||
23 | + this.groups.push(group); | ||
24 | + return this.save(); | ||
25 | +}; | ||
26 | + | ||
27 | +ChallengeSchema.methods.removeGroup = function (group_id) { | ||
28 | + const idx = this.groups.findIndex((item) => item._id === group_id); | ||
29 | + this.groups.splice(idx, 1); | ||
30 | + return this.save(); | ||
31 | +}; | ||
32 | + | ||
33 | +ChallengeSchema.methods.getChallengeName = function () { | ||
34 | + return this.challengeName; | ||
35 | +}; | ||
36 | + | ||
37 | +ChallengeSchema.methods.getStartDate = function () { | ||
38 | + return this.startDate; | ||
39 | +}; | ||
40 | + | ||
41 | +ChallengeSchema.methods.getEndDate = function () { | ||
42 | + return this.endDate; | ||
43 | +}; | ||
44 | + | ||
45 | +ChallengeSchema.methods.getDurationPerSession = function () { | ||
46 | + return this.durationPerSession; | ||
47 | +}; | ||
48 | + | ||
49 | +ChallengeSchema.methods.getGoalPerSession = function () { | ||
50 | + return this.goalPerSession; | ||
51 | +}; | ||
52 | + | ||
53 | +ChallengeSchema.methods.getGroups = function () { | ||
54 | + return this.groups; | ||
55 | +}; | ||
56 | + | ||
57 | +ChallengeSchema.methods.serialize = function () { | ||
58 | + return this.toJSON(); | ||
59 | +}; | ||
60 | + | ||
61 | +const Challenge = mongoose.model("Challenge", ChallengeSchema); | ||
62 | +module.exports = Challenge; |
jaksimsamil-server/src/models/problem.js
0 → 100644
1 | +const mongoose=require('mongoose'); | ||
2 | + | ||
3 | +const {Schema}=mongoose; | ||
4 | + | ||
5 | +const ProblemSchema=new Schema({ | ||
6 | + problemNum: {type: Number, required: true, unique: true}, | ||
7 | + problemTitle: {type: String, required: true}, | ||
8 | + solvedacLevel: {type: Number}, | ||
9 | + sumbitNum: {type: Number, required: true}, | ||
10 | + correctNum: {type: Number, required: true}, | ||
11 | + category: {type:[String]} | ||
12 | +}); | ||
13 | + | ||
14 | +ProblemSchema.statics.findByProblemNum=function(problemNum){ | ||
15 | + return this.findOne({problemNum:problemNum}); | ||
16 | +} | ||
17 | + | ||
18 | +ProblemSchema.methods.addCategory=function(category){ | ||
19 | + this.category.push(category); | ||
20 | + return this.save(); | ||
21 | +} | ||
22 | + | ||
23 | +ProblemSchema.methods.removeCategory=function(category){ | ||
24 | + const idx=this.category.findIndex(item=>item===category); | ||
25 | + this.splice(idx,1); | ||
26 | + return this.save(); | ||
27 | +} | ||
28 | + | ||
29 | +ProblemSchema.methods.getProblemNum=function(){ | ||
30 | + return this.problemNum; | ||
31 | +} | ||
32 | + | ||
33 | +ProblemSchema.methods.getProblemTitle=function(){ | ||
34 | + return this.problemTitle; | ||
35 | +} | ||
36 | + | ||
37 | +ProblemSchema.methods.getSolvedacLevel=function(){ | ||
38 | + return this.solvedacLevel; | ||
39 | +} | ||
40 | + | ||
41 | +ProblemSchema.methods.getSumbitNum=function(){ | ||
42 | + return this.sumbitNum; | ||
43 | +} | ||
44 | + | ||
45 | +ProblemSchema.methods.getCorrectNum=function(){ | ||
46 | + return this.correctNum; | ||
47 | +} | ||
48 | + | ||
49 | +ProblemSchema.methods.getCategory=function(){ | ||
50 | + return this.category; | ||
51 | +} | ||
52 | + | ||
53 | +ProblemSchema.methods.serialize=function(){ | ||
54 | + return this.toJSON(); | ||
55 | +} | ||
56 | + | ||
57 | +const Problem=mongoose.model('Problem',ProblemSchema); | ||
58 | +module.exports=Problem; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -6,8 +6,10 @@ const ProfileSchema = new Schema({ | ... | @@ -6,8 +6,10 @@ const ProfileSchema = new Schema({ |
6 | username: { type: String, required: true, unique: true }, | 6 | username: { type: String, required: true, unique: true }, |
7 | userBJID: String, | 7 | userBJID: String, |
8 | solvedBJ: Object, | 8 | solvedBJ: Object, |
9 | + solvedBJ_date: Object, | ||
9 | friendList: [String], | 10 | friendList: [String], |
10 | slackWebHookURL: String, | 11 | slackWebHookURL: String, |
12 | + goalNum: Number, | ||
11 | }); | 13 | }); |
12 | ProfileSchema.statics.findByUsername = function (username) { | 14 | ProfileSchema.statics.findByUsername = function (username) { |
13 | return this.findOne({ username }); | 15 | return this.findOne({ username }); |
... | @@ -15,6 +17,20 @@ ProfileSchema.statics.findByUsername = function (username) { | ... | @@ -15,6 +17,20 @@ ProfileSchema.statics.findByUsername = function (username) { |
15 | ProfileSchema.methods.getBJID = function () { | 17 | ProfileSchema.methods.getBJID = function () { |
16 | return this.userBJID; | 18 | return this.userBJID; |
17 | }; | 19 | }; |
20 | +ProfileSchema.methods.getBJdata = function () { | ||
21 | + return this.solvedBJ; | ||
22 | +}; | ||
23 | +ProfileSchema.methods.getslackURL = function () { | ||
24 | + return this.slackWebHookURL; | ||
25 | +}; | ||
26 | +ProfileSchema.methods.getgoalNum = function () { | ||
27 | + return this.goalNum; | ||
28 | +}; | ||
29 | +ProfileSchema.methods.getTodaySovled = function () { | ||
30 | + if (this.solvedBJ_date) { | ||
31 | + return this.solvedBJ_date.presentNum; | ||
32 | + } | ||
33 | +}; | ||
18 | 34 | ||
19 | ProfileSchema.methods.serialize = function () { | 35 | ProfileSchema.methods.serialize = function () { |
20 | const data = this.toJSON(); | 36 | const data = this.toJSON(); | ... | ... |
1 | -/* | 1 | +let moment = require("moment"); |
2 | -2. 현재 날짜와의 차이 => | 2 | +const problem_set = require("../data/problem_set"); |
3 | -3. 오늘 푼 문제 => 앞에서부터 순회하면서 데이트 같은거 찾기 | 3 | +const compareBJ = require("./compareBJ"); |
4 | -3. 최근 일주일간 푼 문제 수 => 앞에서부터 순회하면서 - 값이 | ||
5 | -4. 추천 문제 => 정규 셋에서 없는거 찾기 | ||
6 | -5. 날짜별로 묶기. | ||
7 | -데이터베이스에서 처리하자 | ||
8 | -*/ | ||
9 | - | ||
10 | -let moment = require('moment'); | ||
11 | - | ||
12 | exports.analyzeBJ = function (solvedBJ) { | 4 | exports.analyzeBJ = function (solvedBJ) { |
13 | try { | 5 | try { |
14 | if (solvedBJ) { | 6 | if (solvedBJ) { |
15 | - console.log(solvedBJ[0]); | ||
16 | let presentDate = moment(); | 7 | let presentDate = moment(); |
17 | - let presentDate_str = presentDate.format('YYYYMMDD'); | 8 | + let presentDate_str = presentDate.format("YYYYMMDD"); |
18 | - let latestDate = moment(solvedBJ[0].solved_date, 'YYYYMMDD'); | 9 | + let latestDate = moment(solvedBJ[0].solved_date, "YYYYMMDD"); |
19 | - let difflatest = presentDate.diff(latestDate, 'days'); | 10 | + let difflatest = presentDate.diff(latestDate, "days"); |
11 | + let latestSolve = solvedBJ[0]; | ||
20 | 12 | ||
21 | let solvedBJbyDATE = {}; | 13 | let solvedBJbyDATE = {}; |
22 | for (let i = 0; i < solvedBJ.length; i++) { | 14 | for (let i = 0; i < solvedBJ.length; i++) { |
... | @@ -33,14 +25,46 @@ exports.analyzeBJ = function (solvedBJ) { | ... | @@ -33,14 +25,46 @@ exports.analyzeBJ = function (solvedBJ) { |
33 | presentDate_str in solvedBJbyDATE | 25 | presentDate_str in solvedBJbyDATE |
34 | ? solvedBJbyDATE[presentDate_str].length | 26 | ? solvedBJbyDATE[presentDate_str].length |
35 | : 0; | 27 | : 0; |
28 | + | ||
29 | + let weekNUM = 0; | ||
30 | + let monthNUM = 0; | ||
31 | + let totalNUM = 0; | ||
32 | + for (let i = 0; i < solvedBJ.length; i++) { | ||
33 | + let diffDate = presentDate.diff( | ||
34 | + moment(solvedBJ[i].solved_date, "YYYYMMDD"), | ||
35 | + "days" | ||
36 | + ); | ||
37 | + if (diffDate <= 7) { | ||
38 | + weekNUM++; | ||
39 | + monthNUM++; | ||
40 | + totalNUM++; | ||
41 | + } else if (diffDate <= 31) { | ||
42 | + monthNUM++; | ||
43 | + totalNUM++; | ||
44 | + } else { | ||
45 | + totalNUM++; | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | + let unsolved_data = compareBJ.compareBJ( | ||
50 | + solvedBJ, | ||
51 | + problem_set.problem_set | ||
52 | + ); | ||
53 | + let recommend_data = compareBJ.randomItem(unsolved_data); | ||
54 | + | ||
36 | let returnOBJ = { | 55 | let returnOBJ = { |
37 | - latestDate: latestDate.format('YYYYMMDD'), | 56 | + latestDate: latestDate.format("YYYYMMDD"), |
38 | difflatest: difflatest, | 57 | difflatest: difflatest, |
39 | latestNum: latestNum, | 58 | latestNum: latestNum, |
40 | presentNum: presentNum, | 59 | presentNum: presentNum, |
60 | + weekNum: weekNUM, | ||
61 | + monthNum: monthNUM, | ||
62 | + totalNum: totalNUM, | ||
41 | solvedBJbyDATE: solvedBJbyDATE, | 63 | solvedBJbyDATE: solvedBJbyDATE, |
64 | + latestSolve: latestSolve, | ||
65 | + recommend_data: recommend_data, | ||
42 | }; | 66 | }; |
43 | - console.log(returnOBJ); | 67 | + |
44 | return returnOBJ; | 68 | return returnOBJ; |
45 | } | 69 | } |
46 | } catch (e) { | 70 | } catch (e) { | ... | ... |
1 | -/* | ||
2 | -집중을 해보자. | ||
3 | -새거와 데이터가 있다. | ||
4 | -데이터 기준으로 새거에 자료가 있으면 넘어가기 | ||
5 | -없으면 새 배열에 추가 | ||
6 | -키만 모아둔 리스트를 만들자. | ||
7 | -그렇게 해서 | ||
8 | -반복은 새거 길이만큼 | ||
9 | -데이터에 있으면 추가 X | ||
10 | -없으면 추가 | ||
11 | -그렇게 반환 | ||
12 | -*/ | ||
13 | - | ||
14 | exports.compareBJ = function (solvedBJ_new, problem_set) { | 1 | exports.compareBJ = function (solvedBJ_new, problem_set) { |
15 | try { | 2 | try { |
16 | let new_obj = []; | 3 | let new_obj = []; |
17 | - for (let i = 0; i < solvedBJ.length; i++) { | 4 | + |
18 | - if (solvedBJ_new[i].problem_number in problem_set) { | 5 | + for (let i = 0; i < problem_set.length; i++) { |
19 | - new_obj.push(solvedBJ_new[i]); | 6 | + let found = false; |
7 | + for (let j = 0; j < solvedBJ_new.length; j++) { | ||
8 | + if (solvedBJ_new[j].problem_number == problem_set[i].problem_number) { | ||
9 | + found = true; | ||
10 | + break; | ||
11 | + } | ||
20 | } | 12 | } |
13 | + if (!found) { | ||
14 | + new_obj.push(problem_set[i]); | ||
21 | } | 15 | } |
22 | - console.log(new_obj); | 16 | + } |
17 | + return new_obj; | ||
23 | } catch (e) { | 18 | } catch (e) { |
24 | console.log(e); | 19 | console.log(e); |
25 | } | 20 | } |
26 | }; | 21 | }; |
22 | + | ||
23 | +exports.randomItem = function (a) { | ||
24 | + return a[Math.floor(Math.random() * a.length)]; | ||
25 | +}; | ... | ... |
1 | const Slack = require("slack-node"); // 슬랙 모듈 사용 | 1 | const Slack = require("slack-node"); // 슬랙 모듈 사용 |
2 | 2 | ||
3 | +/* | ||
3 | const webhookUri = | 4 | const webhookUri = |
4 | - "https://hooks.slack.com/services/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"; // Webhook URL | 5 | + "https://hooks.slack.com/services/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"; // Webhook URL |
6 | +*/ | ||
5 | 7 | ||
6 | -const slack = new Slack(); | 8 | +exports.send = async (message, webhookUri) => { |
7 | -slack.setWebhook(webhookUri); | 9 | + const slack = new Slack(); |
8 | - | 10 | + slack.setWebhook(webhookUri); |
9 | -const send = async (message) => { | ||
10 | slack.webhook( | 11 | slack.webhook( |
11 | { | 12 | { |
12 | text: message, | 13 | text: message, |
... | @@ -16,5 +17,3 @@ const send = async (message) => { | ... | @@ -16,5 +17,3 @@ const send = async (message) => { |
16 | } | 17 | } |
17 | ); | 18 | ); |
18 | }; | 19 | }; |
19 | - | ||
20 | -send("hello"); | ... | ... |
1 | var getBJ = require("./getBJ"); | 1 | var getBJ = require("./getBJ"); |
2 | var fs = require("fs"); | 2 | var fs = require("fs"); |
3 | 3 | ||
4 | -let dataset = [ | ||
5 | - "1517", | ||
6 | - "2448", | ||
7 | - "1891", | ||
8 | - "1074", | ||
9 | - "2263", | ||
10 | - "1780", | ||
11 | - "11728", | ||
12 | - "10816", | ||
13 | - "10815", | ||
14 | - "2109", | ||
15 | - "1202", | ||
16 | - "1285", | ||
17 | - "2138", | ||
18 | - "1080", | ||
19 | - "11399", | ||
20 | - "1931", | ||
21 | - "11047", | ||
22 | - "15666", | ||
23 | - "15665", | ||
24 | - "15664", | ||
25 | - "15663", | ||
26 | - "15657", | ||
27 | - "15656", | ||
28 | - "15655", | ||
29 | - "15654", | ||
30 | - "15652", | ||
31 | - "15651", | ||
32 | - "15650", | ||
33 | - "15649", | ||
34 | - "6603", | ||
35 | - "10971", | ||
36 | - "10819", | ||
37 | - "10973", | ||
38 | - "10974", | ||
39 | - "10972", | ||
40 | - "7576", | ||
41 | - "1248", | ||
42 | - "2529", | ||
43 | - "15661", | ||
44 | - "14501", | ||
45 | - "1759", | ||
46 | - "14391", | ||
47 | - "14889", | ||
48 | - "1182", | ||
49 | - "11723", | ||
50 | - "1748", | ||
51 | - "6064", | ||
52 | - "1107", | ||
53 | - "3085", | ||
54 | - "2309", | ||
55 | - "1748", | ||
56 | - "14500", | ||
57 | - "1107", | ||
58 | - "1476", | ||
59 | - "3085", | ||
60 | - "2309", | ||
61 | - "1261", | ||
62 | - "13549", | ||
63 | - "14226", | ||
64 | - "13913", | ||
65 | - "1697", | ||
66 | - "1967", | ||
67 | - "1167", | ||
68 | - "11725", | ||
69 | - "2250", | ||
70 | - "1991", | ||
71 | - "7562", | ||
72 | - "2178", | ||
73 | - "4963", | ||
74 | - "2667", | ||
75 | - "1707", | ||
76 | - "11724", | ||
77 | - "1260", | ||
78 | - "13023", | ||
79 | - "11652", | ||
80 | - "1377", | ||
81 | - "11004", | ||
82 | - "10825", | ||
83 | - "2751", | ||
84 | - "9461", | ||
85 | - "1699", | ||
86 | - "9095", | ||
87 | - "2225", | ||
88 | - "2133", | ||
89 | - "11727", | ||
90 | - "11726", | ||
91 | - "1463", | ||
92 | - "2748", | ||
93 | - "2747", | ||
94 | - "11656", | ||
95 | - "10824", | ||
96 | - "2743", | ||
97 | - "10820", | ||
98 | - "10808", | ||
99 | - "11655", | ||
100 | - "11720", | ||
101 | - "1008", | ||
102 | - "10951", | ||
103 | - "2557", | ||
104 | - "1021", | ||
105 | - "1966", | ||
106 | - "2164", | ||
107 | - "10799", | ||
108 | - "17413", | ||
109 | - "10866", | ||
110 | - "1158", | ||
111 | - "10845", | ||
112 | - "1406", | ||
113 | - "1874", | ||
114 | - "9012", | ||
115 | - "9093", | ||
116 | - "10828", | ||
117 | - "11721", | ||
118 | - "11719", | ||
119 | - "11718", | ||
120 | - "10953", | ||
121 | - "2558", | ||
122 | - "10814", | ||
123 | - "1181", | ||
124 | - "11651", | ||
125 | - "11650", | ||
126 | - "1427", | ||
127 | - "2108", | ||
128 | - "10989", | ||
129 | - "2751", | ||
130 | - "2750", | ||
131 | - "1436", | ||
132 | - "1018", | ||
133 | - "7568", | ||
134 | - "2231", | ||
135 | - "2798", | ||
136 | - "1002", | ||
137 | - "3053", | ||
138 | - "4153", | ||
139 | - "3009", | ||
140 | - "1085", | ||
141 | - "9020", | ||
142 | - "4948", | ||
143 | - "1929", | ||
144 | - "2581", | ||
145 | - "1978", | ||
146 | - "2292", | ||
147 | - "6064", | ||
148 | - "2775", | ||
149 | - "10250", | ||
150 | - "2869", | ||
151 | - "1011", | ||
152 | - "1193", | ||
153 | - "2839", | ||
154 | - "1712", | ||
155 | - "1316", | ||
156 | - "2941", | ||
157 | - "5622", | ||
158 | - "2908", | ||
159 | - "1152", | ||
160 | - "1157", | ||
161 | - "2675", | ||
162 | - "10809", | ||
163 | - "11720", | ||
164 | - "11654", | ||
165 | - "11729", | ||
166 | - "2447", | ||
167 | - "3052", | ||
168 | - "10818", | ||
169 | - "10872", | ||
170 | - "10870", | ||
171 | - "1065", | ||
172 | - "4673", | ||
173 | - "15596", | ||
174 | - "4344", | ||
175 | - "2920", | ||
176 | - "8958", | ||
177 | - "1546", | ||
178 | - "2577", | ||
179 | - "2562", | ||
180 | - "1110", | ||
181 | - "10951", | ||
182 | - "10952", | ||
183 | - "10871", | ||
184 | - "2439", | ||
185 | - "2438", | ||
186 | - "11022", | ||
187 | - "11021", | ||
188 | - "2742", | ||
189 | - "2741", | ||
190 | - "15552", | ||
191 | - "8393", | ||
192 | - "10950", | ||
193 | - "2739", | ||
194 | - "10817", | ||
195 | - "2884", | ||
196 | - "2753", | ||
197 | - "9498", | ||
198 | - "1330", | ||
199 | - "2588", | ||
200 | - "10430", | ||
201 | - "10869", | ||
202 | - "1008", | ||
203 | - "10998", | ||
204 | - "7287", | ||
205 | - "10172", | ||
206 | - "10171", | ||
207 | - "10718", | ||
208 | - "1001", | ||
209 | - "1000", | ||
210 | - "2557", | ||
211 | -]; | ||
212 | - | ||
213 | const test = async (userid) => { | 4 | const test = async (userid) => { |
214 | let lst = await getBJ.getBJ(userid); | 5 | let lst = await getBJ.getBJ(userid); |
215 | let return_lst = []; | 6 | let return_lst = []; |
... | @@ -217,7 +8,7 @@ const test = async (userid) => { | ... | @@ -217,7 +8,7 @@ const test = async (userid) => { |
217 | return_lst.push(lst[i].problem_number); | 8 | return_lst.push(lst[i].problem_number); |
218 | } | 9 | } |
219 | 10 | ||
220 | - var stringJson = JSON.stringify(return_lst) + "\n"; | 11 | + var stringJson = JSON.stringify(lst) + "\n"; |
221 | fs.open("test.json", "a", "666", function (err, id) { | 12 | fs.open("test.json", "a", "666", function (err, id) { |
222 | if (err) { | 13 | if (err) { |
223 | console.log("file open err!!"); | 14 | console.log("file open err!!"); |
... | @@ -232,4 +23,4 @@ const test = async (userid) => { | ... | @@ -232,4 +23,4 @@ const test = async (userid) => { |
232 | /* | 23 | /* |
233 | 24 | ||
234 | */ | 25 | */ |
235 | -test("jwseo001"); | 26 | +test("thak00"); | ... | ... |
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment