Showing
49 changed files
with
2036 additions
and
71 deletions
jaksimsamil-page/package-lock.json
0 → 100644
This diff could not be displayed because it is too large.
... | @@ -3,13 +3,24 @@ | ... | @@ -3,13 +3,24 @@ |
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "dependencies": { | 5 | "dependencies": { |
6 | + "@material-ui/core": "^4.10.2", | ||
6 | "@testing-library/jest-dom": "^4.2.4", | 7 | "@testing-library/jest-dom": "^4.2.4", |
7 | "@testing-library/react": "^9.3.2", | 8 | "@testing-library/react": "^9.3.2", |
8 | "@testing-library/user-event": "^7.1.2", | 9 | "@testing-library/user-event": "^7.1.2", |
10 | + "axios": "^0.19.2", | ||
11 | + "immer": "^7.0.1", | ||
12 | + "include-media": "^1.4.9", | ||
13 | + "open-color": "^1.7.0", | ||
9 | "react": "^16.13.1", | 14 | "react": "^16.13.1", |
10 | "react-dom": "^16.13.1", | 15 | "react-dom": "^16.13.1", |
16 | + "react-redux": "^7.2.0", | ||
11 | "react-router-dom": "^5.2.0", | 17 | "react-router-dom": "^5.2.0", |
12 | - "react-scripts": "3.4.1" | 18 | + "react-scripts": "3.4.1", |
19 | + "redux": "^4.0.5", | ||
20 | + "redux-actions": "^2.6.5", | ||
21 | + "redux-devtools-extension": "^2.13.8", | ||
22 | + "redux-saga": "^1.1.3", | ||
23 | + "styled-components": "^5.1.1" | ||
13 | }, | 24 | }, |
14 | "scripts": { | 25 | "scripts": { |
15 | "start": "react-scripts start", | 26 | "start": "react-scripts start", |
... | @@ -31,5 +42,6 @@ | ... | @@ -31,5 +42,6 @@ |
31 | "last 1 firefox version", | 42 | "last 1 firefox version", |
32 | "last 1 safari version" | 43 | "last 1 safari version" |
33 | ] | 44 | ] |
34 | - } | 45 | + }, |
46 | + "proxy": "http://localhost:4000" | ||
35 | } | 47 | } | ... | ... |
1 | import React from 'react'; | 1 | import React from 'react'; |
2 | -import logo from './logo.svg'; | 2 | +import { Route } from 'react-router-dom'; |
3 | import './App.css'; | 3 | import './App.css'; |
4 | +import LoginPage from './pages/LoginPage'; | ||
5 | +import RegisterPage from './pages/RegisterPage'; | ||
6 | +import HomePage from './pages/HomePage'; | ||
7 | +import SettingPage from './pages/SettingPage'; | ||
4 | 8 | ||
5 | function App() { | 9 | function App() { |
6 | return ( | 10 | return ( |
7 | - <div className="App"> | 11 | + <> |
8 | - <header className="App-header"> | 12 | + <Route component={HomePage} path={['/@:username', '/']} exact /> |
9 | - <img src={logo} className="App-logo" alt="logo" /> | 13 | + <Route component={LoginPage} path="/login" /> |
10 | - <p> | 14 | + <Route component={RegisterPage} path="/register" /> |
11 | - Edit <code>src/App.js</code> and save to reload. | 15 | + <Route component={SettingPage} path="/setting" /> |
12 | - </p> | 16 | + </> |
13 | - <a | ||
14 | - className="App-link" | ||
15 | - href="https://reactjs.org" | ||
16 | - target="_blank" | ||
17 | - rel="noopener noreferrer" | ||
18 | - > | ||
19 | - Learn React | ||
20 | - </a> | ||
21 | - </header> | ||
22 | - </div> | ||
23 | ); | 17 | ); |
24 | } | 18 | } |
25 | 19 | ... | ... |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import { Link } from 'react-router-dom'; | ||
4 | +import palette from '../../lib/styles/palette'; | ||
5 | +import Button from '../common/Button'; | ||
6 | + | ||
7 | +const AuthFormBlock = styled.div` | ||
8 | + h3 { | ||
9 | + margin: 0; | ||
10 | + color: ${palette.gray[8]}; | ||
11 | + margin-bottom: 1rem; | ||
12 | + } | ||
13 | +`; | ||
14 | + | ||
15 | +const StyledInput = styled.input` | ||
16 | + font-size: 1rem; | ||
17 | + border: none; | ||
18 | + border-bottom: 1px solid ${palette.gray[5]}; | ||
19 | + padding-bottom: 0.5rem; | ||
20 | + outline: none; | ||
21 | + width: 100%; | ||
22 | + &:focus { | ||
23 | + color: $oc-teal-7; | ||
24 | + border-bottom: 1px solid ${palette.gray[7]}; | ||
25 | + } | ||
26 | + & + & { | ||
27 | + margin-top: 1rem; | ||
28 | + } | ||
29 | +`; | ||
30 | + | ||
31 | +const Footer = styled.div` | ||
32 | + margin-top: 2rem; | ||
33 | + text-align: right; | ||
34 | + a { | ||
35 | + color: ${palette.gray[6]}; | ||
36 | + text-decoration: underline; | ||
37 | + &:hover { | ||
38 | + color: ${palette.gray[9]}; | ||
39 | + } | ||
40 | + } | ||
41 | +`; | ||
42 | + | ||
43 | +const ButtonWithMarginTop = styled(Button)` | ||
44 | + margin-top: 1rem; | ||
45 | +`; | ||
46 | + | ||
47 | +const ErrorMessage = styled.div` | ||
48 | + color: red; | ||
49 | + text-align: center; | ||
50 | + font-size: 0.875rem; | ||
51 | + margin-top: 1rem; | ||
52 | +`; | ||
53 | + | ||
54 | +const textMap = { | ||
55 | + login: '로그인', | ||
56 | + register: '회원가입', | ||
57 | +}; | ||
58 | + | ||
59 | +const AuthForm = ({ type, form, onChange, onSubmit, error }) => { | ||
60 | + const text = textMap[type]; | ||
61 | + return ( | ||
62 | + <AuthFormBlock> | ||
63 | + <h3>{text}</h3> | ||
64 | + <form onSubmit={onSubmit}> | ||
65 | + <StyledInput | ||
66 | + autoComplete="username" | ||
67 | + name="username" | ||
68 | + placeholder="아이디" | ||
69 | + onChange={onChange} | ||
70 | + value={form.username} | ||
71 | + /> | ||
72 | + <StyledInput | ||
73 | + autoComplete="new-password" | ||
74 | + name="password" | ||
75 | + placeholder="비밀번호" | ||
76 | + type="password" | ||
77 | + onChange={onChange} | ||
78 | + value={form.password} | ||
79 | + /> | ||
80 | + {type === 'register' && ( | ||
81 | + <StyledInput | ||
82 | + autoComplete="new-password" | ||
83 | + name="passwordConfirm" | ||
84 | + placeholder="비밀번호 확인" | ||
85 | + type="password" | ||
86 | + onChange={onChange} | ||
87 | + value={form.passwordConfirm} | ||
88 | + /> | ||
89 | + )} | ||
90 | + {error && <ErrorMessage>{error}</ErrorMessage>} | ||
91 | + <ButtonWithMarginTop cyan fullWidth> | ||
92 | + {text} | ||
93 | + </ButtonWithMarginTop> | ||
94 | + </form> | ||
95 | + <Footer> | ||
96 | + {type === 'login' ? ( | ||
97 | + <Link to="/register">회원가입</Link> | ||
98 | + ) : ( | ||
99 | + <Link to="/login">로그인</Link> | ||
100 | + )} | ||
101 | + </Footer> | ||
102 | + </AuthFormBlock> | ||
103 | + ); | ||
104 | +}; | ||
105 | + | ||
106 | +export default AuthForm; |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import palette from '../../lib/styles/palette'; | ||
4 | +import { Link } from 'react-router-dom'; | ||
5 | +/* | ||
6 | +register/login Layout | ||
7 | +*/ | ||
8 | +const AuthTemplateBlock = styled.div` | ||
9 | + position: absolute; | ||
10 | + left: 0; | ||
11 | + top: 0; | ||
12 | + bottom: 0; | ||
13 | + right: 0; | ||
14 | + background: ${palette.gray[2]}; | ||
15 | + display: flex; | ||
16 | + flex-direction: column; | ||
17 | + justify-content: center; | ||
18 | + align-items: center; | ||
19 | +`; | ||
20 | + | ||
21 | +const WhiteBox = styled.div` | ||
22 | + .logo-area { | ||
23 | + display: block; | ||
24 | + padding-bottom: 2rem; | ||
25 | + text-align: center; | ||
26 | + font-weight: bold; | ||
27 | + letter-spacing: 2px; | ||
28 | + } | ||
29 | + box-shadow: 0 0 8px rgba(0, 0, 0, 0.025); | ||
30 | + padding: 2rem; | ||
31 | + width: 360px; | ||
32 | + background: white; | ||
33 | + border-radius: 2px; | ||
34 | +`; | ||
35 | + | ||
36 | +const AuthTemplate = ({ children }) => { | ||
37 | + return ( | ||
38 | + <AuthTemplateBlock> | ||
39 | + <WhiteBox> | ||
40 | + <div className="logo-area"> | ||
41 | + <Link to="/">작심삼일</Link> | ||
42 | + </div> | ||
43 | + {children} | ||
44 | + </WhiteBox> | ||
45 | + </AuthTemplateBlock> | ||
46 | + ); | ||
47 | +}; | ||
48 | + | ||
49 | +export default AuthTemplate; |
1 | +import React from 'react'; | ||
2 | +import styled, { css } from 'styled-components'; | ||
3 | +import palette from '../../lib/styles/palette'; | ||
4 | +import { withRouter } from 'react-router-dom'; | ||
5 | + | ||
6 | +const StyledButton = styled.button` | ||
7 | + border: none; | ||
8 | + border-radius: 4px; | ||
9 | + font-size: 1rem; | ||
10 | + font-weight: bold; | ||
11 | + padding: 0.25rem 1rem; | ||
12 | + color: white; | ||
13 | + outline: none; | ||
14 | + cursor: pointer; | ||
15 | + | ||
16 | + background: ${palette.gray[8]}; | ||
17 | + &:hover { | ||
18 | + background: ${palette.gray[6]}; | ||
19 | + } | ||
20 | + ${props => | ||
21 | + props.fullWidth && | ||
22 | + css` | ||
23 | + padding-top: 0.75rem; | ||
24 | + padding-bottom: 0.75rem; | ||
25 | + width: 100%; | ||
26 | + font-size: 1.125rem; | ||
27 | + `} | ||
28 | + | ||
29 | + ${props => | ||
30 | + props.cyan && | ||
31 | + css` | ||
32 | + background: ${palette.cyan[5]}; | ||
33 | + &:hover { | ||
34 | + background: ${palette.cyan[4]}; | ||
35 | + } | ||
36 | + `} | ||
37 | +`; | ||
38 | + | ||
39 | +const Button = ({ to, history, ...rest }) => { | ||
40 | + const onClick = e => { | ||
41 | + if (to) { | ||
42 | + history.push(to); | ||
43 | + } | ||
44 | + if (rest.onClick) { | ||
45 | + rest.onClick(e); | ||
46 | + } | ||
47 | + }; | ||
48 | + return <StyledButton {...rest} onClick={onClick} />; | ||
49 | +}; | ||
50 | +export default withRouter(Button); |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import { NavLink } from 'react-router-dom'; | ||
4 | + | ||
5 | +const categories = [ | ||
6 | + { | ||
7 | + name: 'home', | ||
8 | + text: '홈', | ||
9 | + }, | ||
10 | + { | ||
11 | + name: 'setting', | ||
12 | + text: '설정', | ||
13 | + }, | ||
14 | +]; | ||
15 | + | ||
16 | +const CategoriesBlock = styled.div` | ||
17 | + display: flex; | ||
18 | + padding: 1rem; | ||
19 | + margin: 0 auto; | ||
20 | + @media screen and (max-width: 768px) { | ||
21 | + width: 100%; | ||
22 | + overflow-x: auto; | ||
23 | + } | ||
24 | +`; | ||
25 | + | ||
26 | +const Category = styled(NavLink)` | ||
27 | + font-size: 1.2rem; | ||
28 | + cursor: pointer; | ||
29 | + white-space: pre; | ||
30 | + text-decoration: none; | ||
31 | + color: inherit; | ||
32 | + padding-bottom: 0.25rem; | ||
33 | + &:hover { | ||
34 | + color: #495057; | ||
35 | + } | ||
36 | + & + & { | ||
37 | + margin-left: 2rem; | ||
38 | + } | ||
39 | + &.active { | ||
40 | + font-weight: 600; | ||
41 | + border-bottom: 2px solid #22b8cf; | ||
42 | + color: #22b8cf; | ||
43 | + &:hover { | ||
44 | + color: #3bc9db; | ||
45 | + } | ||
46 | + } | ||
47 | +`; | ||
48 | + | ||
49 | +const Categories = () => { | ||
50 | + return ( | ||
51 | + <CategoriesBlock> | ||
52 | + {categories.map((c) => ( | ||
53 | + <Category | ||
54 | + activeClassName="active" | ||
55 | + key={c.name} | ||
56 | + exact={c.name === 'home'} | ||
57 | + to={c.name === 'home' ? '/' : `/${c.name}`} | ||
58 | + > | ||
59 | + {c.text} | ||
60 | + </Category> | ||
61 | + ))} | ||
62 | + </CategoriesBlock> | ||
63 | + ); | ||
64 | +}; | ||
65 | + | ||
66 | +export default Categories; |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import Responsive from './Responsive'; | ||
4 | +import Button from './Button'; | ||
5 | +import { Link } from 'react-router-dom'; | ||
6 | +import Categories from './Categories'; | ||
7 | + | ||
8 | +const HeaderBlock = styled.div` | ||
9 | + position: fixed; | ||
10 | + width: 100%; | ||
11 | + background: white; | ||
12 | + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08); | ||
13 | +`; | ||
14 | + | ||
15 | +const Wrapper = styled(Responsive)` | ||
16 | + height: 4rem; | ||
17 | + display: flex; | ||
18 | + align-items: center; | ||
19 | + justify-content: space-between; | ||
20 | + .logo { | ||
21 | + font-size: 1.125rem; | ||
22 | + font-weight: 800; | ||
23 | + letter-spacing: 2px; | ||
24 | + } | ||
25 | + .right { | ||
26 | + display: flex; | ||
27 | + align-items: center; | ||
28 | + } | ||
29 | +`; | ||
30 | + | ||
31 | +const Spacer = styled.div` | ||
32 | + height: 4rem; | ||
33 | +`; | ||
34 | +const UserInfo = styled.div` | ||
35 | + font-weight: 800; | ||
36 | + margin-right: 1rem; | ||
37 | +`; | ||
38 | + | ||
39 | +const Header = ({ user, onLogout, category, onSelect }) => { | ||
40 | + return ( | ||
41 | + <> | ||
42 | + <HeaderBlock> | ||
43 | + <Wrapper> | ||
44 | + <Link to="/" className="logo"> | ||
45 | + 작심삼일 | ||
46 | + </Link> | ||
47 | + <Categories | ||
48 | + category={category} | ||
49 | + onSelect={onSelect} | ||
50 | + className="right" | ||
51 | + /> | ||
52 | + {user ? ( | ||
53 | + <div className="right"> | ||
54 | + <UserInfo>{user.username}</UserInfo> | ||
55 | + <Button onClick={onLogout}>로그아웃</Button> | ||
56 | + </div> | ||
57 | + ) : ( | ||
58 | + <div className="right"> | ||
59 | + <Button to="/login">로그인</Button> | ||
60 | + </div> | ||
61 | + )} | ||
62 | + </Wrapper> | ||
63 | + </HeaderBlock> | ||
64 | + <Spacer /> | ||
65 | + </> | ||
66 | + ); | ||
67 | +}; | ||
68 | + | ||
69 | +export default Header; |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | + | ||
4 | +const ResponsiveBlock = styled.div` | ||
5 | + padding-left: 1rem; | ||
6 | + padding-right: 1rem; | ||
7 | + width: 1024px; | ||
8 | + margin: 0 auto; | ||
9 | + | ||
10 | + @media (max-width: 1024px) { | ||
11 | + width: 768px; | ||
12 | + } | ||
13 | + @media (max-width: 768px) { | ||
14 | + width: 100%; | ||
15 | + } | ||
16 | +`; | ||
17 | + | ||
18 | +const Responsive = ({ children, ...rest }) => { | ||
19 | + return <ResponsiveBlock {...rest}>{children}</ResponsiveBlock>; | ||
20 | +}; | ||
21 | + | ||
22 | +export default Responsive; |
1 | +import React from 'react'; | ||
2 | +import { makeStyles } from '@material-ui/core/styles'; | ||
3 | +import Paper from '@material-ui/core/Paper'; | ||
4 | +import Grid from '@material-ui/core/Grid'; | ||
5 | +import palette from '../../lib/styles/palette'; | ||
6 | +const useStyles = makeStyles((theme) => ({ | ||
7 | + root: { | ||
8 | + flexGrow: 1, | ||
9 | + background: palette.gray[2], | ||
10 | + }, | ||
11 | + paper: { | ||
12 | + padding: theme.spacing(2), | ||
13 | + textAlign: 'center', | ||
14 | + color: theme.palette.text.secondary, | ||
15 | + }, | ||
16 | +})); | ||
17 | +const HomeForm = () => { | ||
18 | + const classes = useStyles(); | ||
19 | + return ( | ||
20 | + <div className={classes.root}> | ||
21 | + <Grid container spacing={3}> | ||
22 | + <Grid item xs={12}> | ||
23 | + <Paper className={classes.paper}>xs=12</Paper> | ||
24 | + </Grid> | ||
25 | + <Grid item xs={6}> | ||
26 | + <Paper className={classes.paper}>xs=6</Paper> | ||
27 | + </Grid> | ||
28 | + <Grid item xs={6}> | ||
29 | + <Paper className={classes.paper}>xs=6</Paper> | ||
30 | + </Grid> | ||
31 | + <Grid item xs={3}> | ||
32 | + <Paper className={classes.paper}>xs=3</Paper> | ||
33 | + </Grid> | ||
34 | + <Grid item xs={3}> | ||
35 | + <Paper className={classes.paper}>xs=3</Paper> | ||
36 | + </Grid> | ||
37 | + <Grid item xs={3}> | ||
38 | + <Paper className={classes.paper}>xs=3</Paper> | ||
39 | + </Grid> | ||
40 | + <Grid item xs={3}> | ||
41 | + <Paper className={classes.paper}>xs=3</Paper> | ||
42 | + </Grid> | ||
43 | + </Grid> | ||
44 | + </div> | ||
45 | + ); | ||
46 | +}; | ||
47 | + | ||
48 | +export default HomeForm; |
1 | +import React from 'react'; | ||
2 | +import { makeStyles } from '@material-ui/core/styles'; | ||
3 | +import styled from 'styled-components'; | ||
4 | +import palette from '../../lib/styles/palette'; | ||
5 | +import Button from '@material-ui/core/Button'; | ||
6 | +import TextField from '@material-ui/core/TextField'; | ||
7 | + | ||
8 | +const useStyles = makeStyles((theme) => ({ | ||
9 | + root: { | ||
10 | + '& > *': { | ||
11 | + margin: theme.spacing(1), | ||
12 | + }, | ||
13 | + }, | ||
14 | +})); | ||
15 | + | ||
16 | +const BJIDForm = ({ onChange, onBJIDSubmit, profile, onSyncBJIDSubmit }) => { | ||
17 | + const classes = useStyles(); | ||
18 | + return ( | ||
19 | + <div> | ||
20 | + <form onSubmit={onBJIDSubmit}> | ||
21 | + <TextField | ||
22 | + name="userBJID" | ||
23 | + onChange={onChange} | ||
24 | + value={profile.userBJID} | ||
25 | + placeholder="백준 아이디" | ||
26 | + label="백준 아이디" | ||
27 | + /> | ||
28 | + <Button variant="outlined" type="submit"> | ||
29 | + 등록 | ||
30 | + </Button> | ||
31 | + </form> | ||
32 | + <Button variant="outlined" onClick={onSyncBJIDSubmit}> | ||
33 | + 동기화 | ||
34 | + </Button> | ||
35 | + </div> | ||
36 | + ); | ||
37 | +}; | ||
38 | +export default BJIDForm; |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import Button from '../common/Button'; | ||
4 | +import palette from '../../lib/styles/palette'; | ||
5 | +import BJIDForm from './BJIDForm'; | ||
6 | +import { makeStyles } from '@material-ui/core/styles'; | ||
7 | +import Paper from '@material-ui/core/Paper'; | ||
8 | +import Grid from '@material-ui/core/Grid'; | ||
9 | + | ||
10 | +const SettingFormBlock = styled.div` | ||
11 | + h3 { | ||
12 | + margin: 0; | ||
13 | + color: ${palette.gray[8]}; | ||
14 | + margin-bottom: 1rem; | ||
15 | + } | ||
16 | + background: ${palette.gray[2]}; | ||
17 | + margin: 0 auto; | ||
18 | + display: flex; | ||
19 | + flex-direction: column; | ||
20 | +`; | ||
21 | +const StyledInput = styled.input` | ||
22 | + font-size: 1rem; | ||
23 | + border: none; | ||
24 | + border-bottom: 1px solid ${palette.gray[5]}; | ||
25 | + padding-bottom: 0.5rem; | ||
26 | + outline: none; | ||
27 | + &:focus { | ||
28 | + color: $oc-teal-7; | ||
29 | + border-bottom: 1px solid ${palette.gray[7]}; | ||
30 | + } | ||
31 | + & + & { | ||
32 | + margin-top: 1rem; | ||
33 | + } | ||
34 | +`; | ||
35 | +const SectionContainer = styled.div` | ||
36 | + display: flex; | ||
37 | +`; | ||
38 | + | ||
39 | +const useStyles = makeStyles((theme) => ({ | ||
40 | + root: { | ||
41 | + flexGrow: 1, | ||
42 | + background: palette.gray[2], | ||
43 | + }, | ||
44 | + paper: { | ||
45 | + margin: 'auto', | ||
46 | + textAlign: 'center', | ||
47 | + padding: 30, | ||
48 | + }, | ||
49 | +})); | ||
50 | + | ||
51 | +const SettingForm = ({ onChange, onBJIDSubmit, profile, onSyncBJIDSubmit }) => { | ||
52 | + const classes = useStyles(); | ||
53 | + return ( | ||
54 | + <div className={classes.root}> | ||
55 | + <Grid container spacing={3}> | ||
56 | + <Grid item xs={12}> | ||
57 | + <Paper className={classes.paper}> | ||
58 | + <h3>{profile.username}</h3> | ||
59 | + </Paper> | ||
60 | + </Grid> | ||
61 | + <Grid container item xs={12}> | ||
62 | + <Paper className={classes.paper} elevation={3}> | ||
63 | + <BJIDForm | ||
64 | + profile={profile} | ||
65 | + onChange={onChange} | ||
66 | + onBJIDSubmit={onBJIDSubmit} | ||
67 | + onSyncBJIDSubmit={onSyncBJIDSubmit} | ||
68 | + /> | ||
69 | + </Paper> | ||
70 | + </Grid> | ||
71 | + </Grid> | ||
72 | + </div> | ||
73 | + ); | ||
74 | +}; | ||
75 | + | ||
76 | +export default SettingForm; |
1 | +import React, { useEffect, useState } from 'react'; | ||
2 | +import { useDispatch, useSelector } from 'react-redux'; | ||
3 | +import { withRouter } from 'react-router-dom'; | ||
4 | +import { changeField, initializeForm, login } from '../../modules/auth'; | ||
5 | +import AuthForm from '../../components/auth/AuthForm'; | ||
6 | +import { check } from '../../modules/user'; | ||
7 | + | ||
8 | +const LoginForm = ({ history }) => { | ||
9 | + const dispatch = useDispatch(); | ||
10 | + const [error, setError] = useState(null); | ||
11 | + const { form, auth, authError, user } = useSelector(({ auth, user }) => ({ | ||
12 | + form: auth.login, | ||
13 | + auth: auth.auth, | ||
14 | + authError: auth.authError, | ||
15 | + user: user.user, | ||
16 | + })); | ||
17 | + | ||
18 | + const onChange = (e) => { | ||
19 | + const { value, name } = e.target; | ||
20 | + dispatch( | ||
21 | + changeField({ | ||
22 | + form: 'login', | ||
23 | + key: name, | ||
24 | + value, | ||
25 | + }), | ||
26 | + ); | ||
27 | + }; | ||
28 | + | ||
29 | + const onSubmit = (e) => { | ||
30 | + e.preventDefault(); | ||
31 | + const { username, password } = form; | ||
32 | + dispatch(login({ username, password })); | ||
33 | + }; | ||
34 | + | ||
35 | + useEffect(() => { | ||
36 | + dispatch(initializeForm('login')); | ||
37 | + }, [dispatch]); | ||
38 | + | ||
39 | + useEffect(() => { | ||
40 | + if (authError) { | ||
41 | + console.log('Error Occured'); | ||
42 | + console.log(authError); | ||
43 | + setError('로그인 실패'); | ||
44 | + return; | ||
45 | + } | ||
46 | + if (auth) { | ||
47 | + console.log('Login Success'); | ||
48 | + dispatch(check()); | ||
49 | + } | ||
50 | + }, [auth, authError, dispatch]); | ||
51 | + | ||
52 | + useEffect(() => { | ||
53 | + if (user) { | ||
54 | + history.push('/'); | ||
55 | + try { | ||
56 | + localStorage.setItem('user', JSON.stringify(user)); | ||
57 | + } catch (e) { | ||
58 | + console.log('localStorage is not working'); | ||
59 | + } | ||
60 | + console.log(user); | ||
61 | + } | ||
62 | + }, [history, user]); | ||
63 | + return ( | ||
64 | + <AuthForm | ||
65 | + type="login" | ||
66 | + form={form} | ||
67 | + onChange={onChange} | ||
68 | + onSubmit={onSubmit} | ||
69 | + error={error} | ||
70 | + ></AuthForm> | ||
71 | + ); | ||
72 | +}; | ||
73 | + | ||
74 | +export default withRouter(LoginForm); |
1 | +import React, { useEffect, useState } from 'react'; | ||
2 | +import { useDispatch, useSelector } from 'react-redux'; | ||
3 | +import { changeField, initializeForm, register } from '../../modules/auth'; | ||
4 | +import AuthForm from '../../components/auth/AuthForm'; | ||
5 | +import { check } from '../../modules/user'; | ||
6 | +import { withRouter } from 'react-router-dom'; | ||
7 | + | ||
8 | +const RegisterForm = ({ history }) => { | ||
9 | + const [error, setError] = useState(null); | ||
10 | + const dispatch = useDispatch(); | ||
11 | + const { form, auth, authError, user } = useSelector(({ auth, user }) => ({ | ||
12 | + form: auth.register, | ||
13 | + auth: auth.auth, | ||
14 | + authError: auth.authError, | ||
15 | + user: user.user, | ||
16 | + })); | ||
17 | + | ||
18 | + const onChange = (e) => { | ||
19 | + const { value, name } = e.target; | ||
20 | + dispatch( | ||
21 | + changeField({ | ||
22 | + form: 'register', | ||
23 | + key: name, | ||
24 | + value, | ||
25 | + }), | ||
26 | + ); | ||
27 | + }; | ||
28 | + | ||
29 | + const onSubmit = (e) => { | ||
30 | + e.preventDefault(); | ||
31 | + const { username, password, passwordConfirm } = form; | ||
32 | + if ([username, password, passwordConfirm].includes('')) { | ||
33 | + setError('빈 칸을 모두 입력하세요'); | ||
34 | + return; | ||
35 | + } | ||
36 | + if (password !== passwordConfirm) { | ||
37 | + setError('비밀번호가 일치하지 않습니다.'); | ||
38 | + changeField({ form: 'register', key: 'password', value: '' }); | ||
39 | + changeField({ form: 'register', key: 'passwordConfirm', value: '' }); | ||
40 | + return; | ||
41 | + } | ||
42 | + dispatch(register({ username, password })); | ||
43 | + }; | ||
44 | + | ||
45 | + useEffect(() => { | ||
46 | + dispatch(initializeForm('register')); | ||
47 | + }, [dispatch]); | ||
48 | + useEffect(() => { | ||
49 | + if (authError) { | ||
50 | + if (authError.response.status === 409) { | ||
51 | + setError('이미 존재하는 계정명입니다.'); | ||
52 | + return; | ||
53 | + } | ||
54 | + setError('회원가입 실패'); | ||
55 | + return; | ||
56 | + } | ||
57 | + | ||
58 | + if (auth) { | ||
59 | + console.log('Register Success!'); | ||
60 | + console.log(auth); | ||
61 | + dispatch(check()); | ||
62 | + } | ||
63 | + }, [auth, authError, dispatch]); | ||
64 | + | ||
65 | + useEffect(() => { | ||
66 | + if (user) { | ||
67 | + console.log('SUCCESS check API'); | ||
68 | + history.push('/'); | ||
69 | + try { | ||
70 | + localStorage.setItem('user', JSON.stringify(user)); | ||
71 | + } catch (e) { | ||
72 | + console.log('localStorage is not working'); | ||
73 | + } | ||
74 | + } | ||
75 | + }, [history, user]); | ||
76 | + return ( | ||
77 | + <AuthForm | ||
78 | + type="register" | ||
79 | + form={form} | ||
80 | + onChange={onChange} | ||
81 | + onSubmit={onSubmit} | ||
82 | + error={error} | ||
83 | + ></AuthForm> | ||
84 | + ); | ||
85 | +}; | ||
86 | + | ||
87 | +export default withRouter(RegisterForm); |
1 | +import React from 'react'; | ||
2 | +import { useSelector, useDispatch } from 'react-redux'; | ||
3 | +import Header from '../../components/common/Header'; | ||
4 | +import { logout } from '../../modules/user'; | ||
5 | +const HeaderContainer = () => { | ||
6 | + const { user } = useSelector(({ user }) => ({ user: user.user })); | ||
7 | + | ||
8 | + const dispatch = useDispatch(); | ||
9 | + const onLogout = () => { | ||
10 | + dispatch(logout()); | ||
11 | + }; | ||
12 | + return <Header user={user} onLogout={onLogout} />; | ||
13 | +}; | ||
14 | +export default HeaderContainer; |
1 | +import React, { useEffect, useState } from 'react'; | ||
2 | +import { useDispatch, useSelector } from 'react-redux'; | ||
3 | +import { withRouter } from 'react-router-dom'; | ||
4 | +import HomeForm from '../../components/home/HomeForm'; | ||
5 | +import { getPROFILE } from '../../modules/profile'; | ||
6 | +import { analyzeBJ } from '../../lib/util/analyzeBJ'; | ||
7 | +const HomeContainer = ({ history }) => { | ||
8 | + const dispatch = useDispatch(); | ||
9 | + const [isLogin, setLogin] = useState(false); | ||
10 | + const { user, profile } = useSelector(({ user, profile }) => ({ | ||
11 | + user: user.user, | ||
12 | + profile: profile, | ||
13 | + })); | ||
14 | + useEffect(() => { | ||
15 | + analyzeBJ(profile.solvedBJ); | ||
16 | + }, [profile.solvedBJ]); | ||
17 | + useEffect(() => { | ||
18 | + setLogin(true); | ||
19 | + if (user) { | ||
20 | + let username = user.username; | ||
21 | + dispatch(getPROFILE({ username })); | ||
22 | + } | ||
23 | + }, [dispatch, user]); | ||
24 | + return <HomeForm />; | ||
25 | +}; | ||
26 | +export default withRouter(HomeContainer); |
1 | +import React, { useEffect, useState } from 'react'; | ||
2 | +import { useDispatch, useSelector } from 'react-redux'; | ||
3 | +import { withRouter } from 'react-router-dom'; | ||
4 | +import { | ||
5 | + changeField, | ||
6 | + setBJID, | ||
7 | + getPROFILE, | ||
8 | + syncBJID, | ||
9 | + initializeProfile, | ||
10 | +} from '../../modules/profile'; | ||
11 | +import SettingForm from '../../components/setting/SettingForm'; | ||
12 | + | ||
13 | +const SettingContainer = ({ history }) => { | ||
14 | + const dispatch = useDispatch(); | ||
15 | + const { user, profile } = useSelector(({ user, profile }) => ({ | ||
16 | + user: user.user, | ||
17 | + profile: profile, | ||
18 | + })); | ||
19 | + | ||
20 | + const onChange = (e) => { | ||
21 | + const { value, name } = e.target; | ||
22 | + dispatch( | ||
23 | + changeField({ | ||
24 | + key: name, | ||
25 | + value: value, | ||
26 | + }), | ||
27 | + ); | ||
28 | + }; | ||
29 | + | ||
30 | + const onSyncBJIDSubmit = (e) => { | ||
31 | + e.preventDefault(); | ||
32 | + let username = profile.username; | ||
33 | + dispatch(syncBJID({ username })); | ||
34 | + }; | ||
35 | + | ||
36 | + const onBJIDSubmit = (e) => { | ||
37 | + e.preventDefault(); | ||
38 | + let username = profile.username; | ||
39 | + let userBJID = profile.userBJID; | ||
40 | + | ||
41 | + dispatch(setBJID({ username, userBJID })); | ||
42 | + }; | ||
43 | + | ||
44 | + useEffect(() => { | ||
45 | + if (!user) { | ||
46 | + alert('로그인이 필요합니다 '); | ||
47 | + history.push('/'); | ||
48 | + } else { | ||
49 | + let username = user.username; | ||
50 | + dispatch(getPROFILE({ username })); | ||
51 | + return () => { | ||
52 | + dispatch(initializeProfile()); | ||
53 | + }; | ||
54 | + } | ||
55 | + }, [dispatch, user, history]); | ||
56 | + | ||
57 | + return ( | ||
58 | + <SettingForm | ||
59 | + type="setting" | ||
60 | + onChange={onChange} | ||
61 | + onBJIDSubmit={onBJIDSubmit} | ||
62 | + onSyncBJIDSubmit={onSyncBJIDSubmit} | ||
63 | + profile={profile} | ||
64 | + ></SettingForm> | ||
65 | + ); | ||
66 | +}; | ||
67 | + | ||
68 | +export default withRouter(SettingContainer); |
... | @@ -5,6 +5,24 @@ body { | ... | @@ -5,6 +5,24 @@ body { |
5 | sans-serif; | 5 | sans-serif; |
6 | -webkit-font-smoothing: antialiased; | 6 | -webkit-font-smoothing: antialiased; |
7 | -moz-osx-font-smoothing: grayscale; | 7 | -moz-osx-font-smoothing: grayscale; |
8 | + box-sizing: border-box; | ||
9 | + min-height: 100%; | ||
10 | +} | ||
11 | + | ||
12 | +#root { | ||
13 | + min-height: 100%; | ||
14 | +} | ||
15 | + | ||
16 | +html { | ||
17 | + height: 100%; | ||
18 | +} | ||
19 | + | ||
20 | +a { | ||
21 | + color: inherit; | ||
22 | + text-decoration: none; | ||
23 | +} | ||
24 | +* { | ||
25 | + box-sizing: inherit; | ||
8 | } | 26 | } |
9 | 27 | ||
10 | code { | 28 | code { | ... | ... |
... | @@ -3,12 +3,41 @@ import ReactDOM from 'react-dom'; | ... | @@ -3,12 +3,41 @@ import ReactDOM from 'react-dom'; |
3 | import './index.css'; | 3 | import './index.css'; |
4 | import App from './App'; | 4 | import App from './App'; |
5 | import * as serviceWorker from './serviceWorker'; | 5 | import * as serviceWorker from './serviceWorker'; |
6 | +import { BrowserRouter } from 'react-router-dom'; | ||
7 | +import { Provider } from 'react-redux'; | ||
8 | +import { createStore, applyMiddleware } from 'redux'; | ||
9 | +import { composeWithDevTools } from 'redux-devtools-extension'; | ||
10 | +import createSagaMiddleware from 'redux-saga'; | ||
11 | +import rootReducer, { rootSaga } from './modules'; | ||
12 | +import { tempSetUser, check } from './modules/user'; | ||
13 | + | ||
14 | +const sagaMiddleware = createSagaMiddleware(); | ||
15 | +const store = createStore( | ||
16 | + rootReducer, | ||
17 | + composeWithDevTools(applyMiddleware(sagaMiddleware)), | ||
18 | +); | ||
19 | + | ||
20 | +function loadUser() { | ||
21 | + try { | ||
22 | + const user = localStorage.getItem('user'); | ||
23 | + if (!user) return; | ||
24 | + | ||
25 | + store.dispatch(tempSetUser(user)); | ||
26 | + store.dispatch(check()); | ||
27 | + } catch (e) { | ||
28 | + console.log('localStorage is not working'); | ||
29 | + } | ||
30 | +} | ||
31 | +sagaMiddleware.run(rootSaga); | ||
32 | +loadUser(); | ||
6 | 33 | ||
7 | ReactDOM.render( | 34 | ReactDOM.render( |
8 | - <React.StrictMode> | 35 | + <Provider store={store}> |
9 | - <App /> | 36 | + <BrowserRouter> |
10 | - </React.StrictMode>, | 37 | + <App /> |
11 | - document.getElementById('root') | 38 | + </BrowserRouter> |
39 | + </Provider>, | ||
40 | + document.getElementById('root'), | ||
12 | ); | 41 | ); |
13 | 42 | ||
14 | // If you want your app to work offline and load faster, you can change | 43 | // If you want your app to work offline and load faster, you can change | ... | ... |
jaksimsamil-page/src/lib/api/auth.js
0 → 100644
1 | +import client from './client'; | ||
2 | + | ||
3 | +export const login = ({ username, password }) => | ||
4 | + client.post('api/auth/login', { username, password }); | ||
5 | + | ||
6 | +export const register = ({ username, password }) => | ||
7 | + client.post('api/auth/register', { username, password }); | ||
8 | + | ||
9 | +export const check = () => client.get('api/auth/check'); | ||
10 | + | ||
11 | +export const logout = () => client.post('/api/auth/logout'); |
jaksimsamil-page/src/lib/api/client.js
0 → 100644
jaksimsamil-page/src/lib/api/profile.js
0 → 100644
1 | +import client from './client'; | ||
2 | + | ||
3 | +export const setBJID = ({ username, userBJID }) => | ||
4 | + client.post('api/profile/setprofile', { | ||
5 | + username: username, | ||
6 | + userBJID: userBJID, | ||
7 | + }); | ||
8 | + | ||
9 | +export const getPROFILE = ({ username }) => | ||
10 | + client.post('api/profile/getprofile', { username }); | ||
11 | + | ||
12 | +export const syncBJ = ({ username }) => | ||
13 | + client.patch('api/profile/syncBJ', { username }); |
1 | +import { call, put } from 'redux-saga/effects'; | ||
2 | +import { startLoading, finishLoading } from '../modules/loading'; | ||
3 | + | ||
4 | +export const createRequestActionTypes = (type) => { | ||
5 | + const SUCCESS = `${type}_SUCCESS`; | ||
6 | + const FAILURE = `${type}_FAILURE`; | ||
7 | + return [type, SUCCESS, FAILURE]; | ||
8 | +}; | ||
9 | + | ||
10 | +export default function createRequestSaga(type, request) { | ||
11 | + const SUCCESS = `${type}_SUCCESS`; | ||
12 | + const FAILURE = `${type}_FAILURE`; | ||
13 | + | ||
14 | + return function* (action) { | ||
15 | + yield put(startLoading(type)); | ||
16 | + try { | ||
17 | + const response = yield call(request, action.payload); | ||
18 | + yield put({ | ||
19 | + type: SUCCESS, | ||
20 | + payload: response.data, | ||
21 | + }); | ||
22 | + } catch (e) { | ||
23 | + yield put({ | ||
24 | + type: FAILURE, | ||
25 | + payload: e, | ||
26 | + error: true, | ||
27 | + }); | ||
28 | + } | ||
29 | + yield put(finishLoading(type)); | ||
30 | + }; | ||
31 | +} |
jaksimsamil-page/src/lib/styles/palette.js
0 → 100644
1 | +// source: https://yeun.github.io/open-color/ | ||
2 | + | ||
3 | +const palette = { | ||
4 | + gray: [ | ||
5 | + '#f8f9fa', | ||
6 | + '#f1f3f5', | ||
7 | + '#e9ecef', | ||
8 | + '#dee2e6', | ||
9 | + '#ced4da', | ||
10 | + '#adb5bd', | ||
11 | + '#868e96', | ||
12 | + '#495057', | ||
13 | + '#343a40', | ||
14 | + '#212529', | ||
15 | + ], | ||
16 | + cyan: [ | ||
17 | + '#e3fafc', | ||
18 | + '#c5f6fa', | ||
19 | + '#99e9f2', | ||
20 | + '#66d9e8', | ||
21 | + '#3bc9db', | ||
22 | + '#22b8cf', | ||
23 | + '#15aabf', | ||
24 | + '#1098ad', | ||
25 | + '#0c8599', | ||
26 | + '#0b7285', | ||
27 | + ], | ||
28 | +}; | ||
29 | + | ||
30 | +export default palette; |
jaksimsamil-page/src/lib/util/analyzeBJ.js
0 → 100644
1 | +/* | ||
2 | +1. 날짜 순 정렬 | ||
3 | +2. 현재 날짜와의 차이 | ||
4 | +3. 최근 일주일간 푼 문제 수 | ||
5 | +4. 추천 문제 | ||
6 | +*/ | ||
7 | +exports.analyzeBJ = function (solvedBJ) { | ||
8 | + console.log(typeof solvedBJ); | ||
9 | + if (solvedBJ) { | ||
10 | + solvedBJ.sort(function (a, b) { | ||
11 | + return a.solvedDate > b.solvedDate | ||
12 | + ? -1 | ||
13 | + : a.solvedDate < b.solvedDate | ||
14 | + ? 1 | ||
15 | + : 0; | ||
16 | + }); | ||
17 | + console.log(solvedBJ); | ||
18 | + } | ||
19 | +}; |
jaksimsamil-page/src/logo.svg
deleted
100644 → 0
1 | -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"> | ||
2 | - <g fill="#61DAFB"> | ||
3 | - <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/> | ||
4 | - <circle cx="420.9" cy="296.5" r="45.7"/> | ||
5 | - <path d="M520.5 78.1z"/> | ||
6 | - </g> | ||
7 | -</svg> |
jaksimsamil-page/src/modules/auth.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | +import produce from 'immer'; | ||
3 | +import { takeLatest } from 'redux-saga/effects'; | ||
4 | +import createRequestSaga, { | ||
5 | + createRequestActionTypes, | ||
6 | +} from '../lib/createRequestSaga'; | ||
7 | +import * as authAPI from '../lib/api/auth'; | ||
8 | +const CHANGE_FIELD = 'auth/CHANGE_FIELD'; | ||
9 | +const INITIALIZE_FORM = 'auth/INITIALIZE_FORM'; | ||
10 | + | ||
11 | +const [REGISTER, REGISTER_SUCCESS, REGISTER_FAILURE] = createRequestActionTypes( | ||
12 | + 'auth/REGISTER', | ||
13 | +); | ||
14 | + | ||
15 | +const [LOGIN, LOGIN_SUCCESS, LOGIN_FAILURE] = createRequestActionTypes( | ||
16 | + 'auth/REGISTER', | ||
17 | +); | ||
18 | + | ||
19 | +export const changeField = createAction( | ||
20 | + CHANGE_FIELD, | ||
21 | + ({ form, key, value }) => ({ | ||
22 | + form, | ||
23 | + key, | ||
24 | + value, | ||
25 | + }), | ||
26 | +); | ||
27 | +export const initializeForm = createAction(INITIALIZE_FORM, (form) => form); | ||
28 | + | ||
29 | +const initalState = { | ||
30 | + register: { | ||
31 | + username: '', | ||
32 | + password: '', | ||
33 | + passwordConfirm: '', | ||
34 | + }, | ||
35 | + login: { | ||
36 | + username: '', | ||
37 | + password: '', | ||
38 | + }, | ||
39 | + auth: null, | ||
40 | + authError: null, | ||
41 | +}; | ||
42 | + | ||
43 | +export const register = createAction(REGISTER, ({ username, password }) => ({ | ||
44 | + username, | ||
45 | + password, | ||
46 | +})); | ||
47 | +export const login = createAction(LOGIN, ({ username, password }) => ({ | ||
48 | + username, | ||
49 | + password, | ||
50 | +})); | ||
51 | + | ||
52 | +const registerSaga = createRequestSaga(REGISTER, authAPI.register); | ||
53 | +const loginSaga = createRequestSaga(LOGIN, authAPI.login); | ||
54 | + | ||
55 | +export function* authSaga() { | ||
56 | + yield takeLatest(REGISTER, registerSaga); | ||
57 | + yield takeLatest(LOGIN, loginSaga); | ||
58 | +} | ||
59 | + | ||
60 | +const auth = handleActions( | ||
61 | + { | ||
62 | + [CHANGE_FIELD]: (state, { payload: { form, key, value } }) => | ||
63 | + produce(state, (draft) => { | ||
64 | + draft[form][key] = value; | ||
65 | + }), | ||
66 | + [INITIALIZE_FORM]: (state, { payload: form }) => ({ | ||
67 | + ...state, | ||
68 | + [form]: initalState[form], | ||
69 | + authError: null, | ||
70 | + }), | ||
71 | + [REGISTER_SUCCESS]: (state, { payload: auth }) => ({ | ||
72 | + ...state, | ||
73 | + authError: null, | ||
74 | + auth, | ||
75 | + }), | ||
76 | + [REGISTER_FAILURE]: (state, { payload: error }) => ({ | ||
77 | + ...state, | ||
78 | + authError: error, | ||
79 | + }), | ||
80 | + [LOGIN_SUCCESS]: (state, { payload: auth }) => ({ | ||
81 | + ...state, | ||
82 | + authError: null, | ||
83 | + auth, | ||
84 | + }), | ||
85 | + [LOGIN_FAILURE]: (state, { payload: error }) => ({ | ||
86 | + ...state, | ||
87 | + authError: error, | ||
88 | + }), | ||
89 | + }, | ||
90 | + initalState, | ||
91 | +); | ||
92 | + | ||
93 | +export default auth; |
jaksimsamil-page/src/modules/index.js
0 → 100644
1 | +import { combineReducers } from 'redux'; | ||
2 | +import { all } from 'redux-saga/effects'; | ||
3 | +import auth, { authSaga } from './auth'; | ||
4 | +import loading from './loading'; | ||
5 | +import user, { userSaga } from './user'; | ||
6 | +import profile, { profileSaga } from './profile'; | ||
7 | + | ||
8 | +const rootReducer = combineReducers({ | ||
9 | + auth, | ||
10 | + loading, | ||
11 | + user, | ||
12 | + profile, | ||
13 | +}); | ||
14 | + | ||
15 | +export function* rootSaga() { | ||
16 | + yield all([authSaga(), userSaga(), profileSaga()]); | ||
17 | +} | ||
18 | + | ||
19 | +export default rootReducer; |
jaksimsamil-page/src/modules/loading.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | + | ||
3 | +const START_LOADING = 'loading/START_LOADING'; | ||
4 | +const FINISH_LOADING = 'loading/FINISH_LOADING'; | ||
5 | + | ||
6 | +export const startLoading = createAction( | ||
7 | + START_LOADING, | ||
8 | + (requestType) => requestType, | ||
9 | +); | ||
10 | + | ||
11 | +export const finishLoading = createAction( | ||
12 | + FINISH_LOADING, | ||
13 | + (requestType) => requestType, | ||
14 | +); | ||
15 | + | ||
16 | +const initialState = {}; | ||
17 | + | ||
18 | +const loading = handleActions( | ||
19 | + { | ||
20 | + [START_LOADING]: (state, action) => ({ | ||
21 | + ...state, | ||
22 | + [action.payload]: true, | ||
23 | + }), | ||
24 | + [FINISH_LOADING]: (state, action) => ({ | ||
25 | + ...state, | ||
26 | + [action.payload]: false, | ||
27 | + }), | ||
28 | + }, | ||
29 | + initialState, | ||
30 | +); | ||
31 | + | ||
32 | +export default loading; |
jaksimsamil-page/src/modules/profile.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | +import createRequestSaga, { | ||
3 | + createRequestActionTypes, | ||
4 | +} from '../lib/createRequestSaga'; | ||
5 | +import produce from 'immer'; | ||
6 | +import * as profileAPI from '../lib/api/profile'; | ||
7 | +import { takeLatest } from 'redux-saga/effects'; | ||
8 | + | ||
9 | +const INITIALIZE = 'profile/INITIALIZE'; | ||
10 | +const CHANGE_FIELD = 'profile/CHANGE_FIELD'; | ||
11 | +const [SET_BJID, SET_BJID_SUCCESS, SET_BJID_FAILURE] = createRequestActionTypes( | ||
12 | + 'profile/SET_BJID', | ||
13 | +); | ||
14 | +const [ | ||
15 | + GET_PROFILE, | ||
16 | + GET_PROFILE_SUCCESS, | ||
17 | + GET_PROFILE_FAILURE, | ||
18 | +] = createRequestActionTypes('profile/GET_PROFILE'); | ||
19 | + | ||
20 | +const [ | ||
21 | + SYNC_BJID, | ||
22 | + SYNC_BJID_SUCCESS, | ||
23 | + SYNC_BJID_FAILURE, | ||
24 | +] = createRequestActionTypes('profile/SYNC_BJID'); | ||
25 | +export const initializeProfile = createAction(INITIALIZE); | ||
26 | +export const syncBJID = createAction(SYNC_BJID, ({ username }) => ({ | ||
27 | + username, | ||
28 | +})); | ||
29 | +export const setBJID = createAction(SET_BJID, ({ username, userBJID }) => ({ | ||
30 | + username, | ||
31 | + userBJID, | ||
32 | +})); | ||
33 | + | ||
34 | +export const changeField = createAction(CHANGE_FIELD, ({ key, value }) => ({ | ||
35 | + key, | ||
36 | + value, | ||
37 | +})); | ||
38 | + | ||
39 | +export const getPROFILE = createAction(GET_PROFILE, ({ username }) => ({ | ||
40 | + username, | ||
41 | +})); | ||
42 | +const initialState = { | ||
43 | + username: '', | ||
44 | + userBJID: '', | ||
45 | + solvedBJ: '', | ||
46 | + friendList: [], | ||
47 | + profileError: '', | ||
48 | +}; | ||
49 | +const getPROFILESaga = createRequestSaga(GET_PROFILE, profileAPI.getPROFILE); | ||
50 | +const setBJIDSaga = createRequestSaga(SET_BJID, profileAPI.setBJID); | ||
51 | +const syncBJIDSaga = createRequestSaga(SYNC_BJID, profileAPI.syncBJ); | ||
52 | +export function* profileSaga() { | ||
53 | + yield takeLatest(SET_BJID, setBJIDSaga); | ||
54 | + yield takeLatest(GET_PROFILE, getPROFILESaga); | ||
55 | + yield takeLatest(SYNC_BJID, syncBJIDSaga); | ||
56 | +} | ||
57 | + | ||
58 | +export default handleActions( | ||
59 | + { | ||
60 | + [INITIALIZE]: (state) => initialState, | ||
61 | + [CHANGE_FIELD]: (state, { payload: { key, value } }) => | ||
62 | + produce(state, (draft) => { | ||
63 | + draft[key] = value; | ||
64 | + }), | ||
65 | + [GET_PROFILE_SUCCESS]: ( | ||
66 | + state, | ||
67 | + { payload: { username, userBJID, solvedBJ, friendList } }, | ||
68 | + ) => ({ | ||
69 | + ...state, | ||
70 | + username: username, | ||
71 | + userBJID: userBJID, | ||
72 | + solvedBJ: solvedBJ, | ||
73 | + friendList: friendList, | ||
74 | + profileError: null, | ||
75 | + }), | ||
76 | + [GET_PROFILE_FAILURE]: (state, { payload: error }) => ({ | ||
77 | + ...state, | ||
78 | + profileError: error, | ||
79 | + }), | ||
80 | + | ||
81 | + [SET_BJID_SUCCESS]: (state, { payload: { userBJID } }) => ({ | ||
82 | + ...state, | ||
83 | + userBJID: userBJID, | ||
84 | + profileError: null, | ||
85 | + }), | ||
86 | + [SET_BJID_FAILURE]: (state, { payload: error }) => ({ | ||
87 | + ...state, | ||
88 | + profileError: error, | ||
89 | + }), | ||
90 | + [SYNC_BJID_SUCCESS]: (state, { payload: { solvedBJ } }) => ({ | ||
91 | + ...state, | ||
92 | + solvedBJ, | ||
93 | + profileError: null, | ||
94 | + }), | ||
95 | + [SYNC_BJID_FAILURE]: (state, { payload: error }) => ({ | ||
96 | + ...state, | ||
97 | + profileError: error, | ||
98 | + }), | ||
99 | + }, | ||
100 | + initialState, | ||
101 | +); |
jaksimsamil-page/src/modules/user.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | +import { takeLatest, call } from 'redux-saga/effects'; | ||
3 | +import * as authAPI from '../lib/api/auth'; | ||
4 | +import createRequestSaga, { | ||
5 | + createRequestActionTypes, | ||
6 | +} from '../lib/createRequestSaga'; | ||
7 | + | ||
8 | +const TEMP_SET_USER = 'user/TEMP_SET_USER'; | ||
9 | +const [CHECK, CHECK_SUCCESS, CHECK_FAILURE] = createRequestActionTypes( | ||
10 | + 'user/CHECK', | ||
11 | +); | ||
12 | +const LOGOUT = 'user/LOGOUT'; | ||
13 | + | ||
14 | +export const tempSetUser = createAction(TEMP_SET_USER, (user) => user); | ||
15 | +export const check = createAction(CHECK); | ||
16 | +export const logout = createAction(LOGOUT); | ||
17 | +const checkSaga = createRequestSaga(CHECK, authAPI.check); | ||
18 | +function checkFailureSaga() { | ||
19 | + try { | ||
20 | + localStorage.removeItem('user'); | ||
21 | + } catch (e) { | ||
22 | + console.log('localStroage is not working'); | ||
23 | + } | ||
24 | +} | ||
25 | +function* logoutSaga() { | ||
26 | + try { | ||
27 | + yield call(authAPI.logout); | ||
28 | + console.log('logout'); | ||
29 | + localStorage.removeItem('user'); | ||
30 | + } catch (e) { | ||
31 | + console.log(e); | ||
32 | + } | ||
33 | +} | ||
34 | +export function* userSaga() { | ||
35 | + yield takeLatest(CHECK, checkSaga); | ||
36 | + yield takeLatest(CHECK_FAILURE, checkFailureSaga); | ||
37 | + yield takeLatest(LOGOUT, logoutSaga); | ||
38 | +} | ||
39 | + | ||
40 | +const initialState = { | ||
41 | + user: null, | ||
42 | + checkError: null, | ||
43 | +}; | ||
44 | + | ||
45 | +export default handleActions( | ||
46 | + { | ||
47 | + [TEMP_SET_USER]: (state, { payload: user }) => ({ | ||
48 | + ...state, | ||
49 | + user, | ||
50 | + }), | ||
51 | + [CHECK_SUCCESS]: (state, { payload: user }) => ({ | ||
52 | + ...state, | ||
53 | + user, | ||
54 | + checkError: null, | ||
55 | + }), | ||
56 | + [CHECK_FAILURE]: (state, { payload: error }) => ({ | ||
57 | + ...state, | ||
58 | + user: null, | ||
59 | + checkError: error, | ||
60 | + }), | ||
61 | + [LOGOUT]: (state) => ({ | ||
62 | + ...state, | ||
63 | + user: null, | ||
64 | + }), | ||
65 | + }, | ||
66 | + initialState, | ||
67 | +); |
jaksimsamil-page/src/pages/HomePage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import HeaderContainer from '../containers/common/HeaderContainer'; | ||
3 | +import HomeContainer from '../containers/home/HomeContainer'; | ||
4 | + | ||
5 | +const HomePage = () => { | ||
6 | + return ( | ||
7 | + <div> | ||
8 | + <HeaderContainer /> | ||
9 | + <HomeContainer /> | ||
10 | + </div> | ||
11 | + ); | ||
12 | +}; | ||
13 | + | ||
14 | +export default HomePage; |
jaksimsamil-page/src/pages/LoginPage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import AuthTemplate from '../components/auth/AuthTemplate'; | ||
3 | +import LoginForm from '../containers/auth/LoginForm'; | ||
4 | + | ||
5 | +const LoginPage = () => { | ||
6 | + return ( | ||
7 | + <AuthTemplate> | ||
8 | + <LoginForm type="login" /> | ||
9 | + </AuthTemplate> | ||
10 | + ); | ||
11 | +}; | ||
12 | + | ||
13 | +export default LoginPage; |
jaksimsamil-page/src/pages/RegisterPage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import AuthTemplate from '../components/auth/AuthTemplate'; | ||
3 | +import RegisterForm from '../containers/auth/RegisterForm'; | ||
4 | + | ||
5 | +const RegisterPage = () => { | ||
6 | + return ( | ||
7 | + <AuthTemplate> | ||
8 | + <RegisterForm type="register" /> | ||
9 | + </AuthTemplate> | ||
10 | + ); | ||
11 | +}; | ||
12 | + | ||
13 | +export default RegisterPage; |
jaksimsamil-page/src/pages/SettingPage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import HeaderContainer from '../containers/common/HeaderContainer'; | ||
3 | +import SettingForm from '../components/setting/SettingForm'; | ||
4 | +import SettingContainer from '../containers/setting/SettingContainer'; | ||
5 | + | ||
6 | +const SettingPage = () => { | ||
7 | + return ( | ||
8 | + <div> | ||
9 | + <HeaderContainer /> | ||
10 | + <SettingContainer></SettingContainer> | ||
11 | + </div> | ||
12 | + ); | ||
13 | +}; | ||
14 | + | ||
15 | +export default SettingPage; |
This diff could not be displayed because it is too large.
... | @@ -18,20 +18,22 @@ | ... | @@ -18,20 +18,22 @@ |
18 | 18 | ||
19 | ## API Table | 19 | ## API Table |
20 | 20 | ||
21 | -| group | description | method | URL | Detail | Auth | | 21 | +| group | description | method | URL | Detail | Auth | |
22 | -| ------- | ------------------------ | ------ | -------------------------- | -------- | --------- | | 22 | +| ------- | --------------------------- | --------- | ------------------------ | -------- | --------- | |
23 | -| user | 유저 등록 | POST | api/user | 바로가기 | JWT Token | | 23 | +| user | 유저 등록 | POST | api/user | 바로가기 | JWT Token | |
24 | -| user | 유저 삭제 | DELETE | api/user:id | 바로가기 | JWT Token | | 24 | +| user | 유저 삭제 | DELETE | api/user:id | 바로가기 | JWT Token | |
25 | -| user | 특정 유저 조회 | GET | api/user:id | 바로가기 | None | | 25 | +| user | 특정 유저 조회 | GET | api/user:id | 바로가기 | None | |
26 | -| user | 전체 유저 조회 | GET | api/user | 바로가기 | JWT Token | | 26 | +| user | 전체 유저 조회 | GET | api/user | 바로가기 | JWT Token | |
27 | -| friend | 유저 친구 등록 | POST | api/friend | 바로가기 | JWT Token | | 27 | +| friend | 유저 친구 등록 | POST | api/friend | 바로가기 | JWT Token | |
28 | -| friend | 유저의 친구 조회 | GET | api/friend:id | 바로가기 | None | | 28 | +| friend | 유저의 친구 조회 | GET | api/friend:id | 바로가기 | None | |
29 | -| profile | 유저가 푼 문제 조회 | GET | api/profile/solved:id | 바로가기 | None | | 29 | +| profile | 유저가 푼 문제 조회(백준) | GET | api/profile/solvedBJ:id | 바로가기 | None | |
30 | -| profile | 유저가 푼 문제 동기화 | Update | api/profile/solved:id | 바로가기 | None | | 30 | +| profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | 바로가기 | None | |
31 | -| profile | 유저가 푼 문제 개수 조회 | GET | api/profile/solvednum:id | 바로가기 | None | | 31 | +| profile | 유저 정보 수정 | POST | api/profile/setprofile | 바로가기 | JWT TOKEN | |
32 | -| profile | 추천 문제 조회 | GET | api/profile/recommendps:id | 바로가기 | None | | 32 | +| profile | 유저 정보 받아오기 | POST | api/profile/getprofile | 바로가기 | JWT | |
33 | -| notify | 슬랙 메시지 전송 요청 | POST | api/notify/slack | 바로가기 | Jwt Token | | 33 | +| profile | 추천 문제 조회 | GET | api/profile/recommend:id | 바로가기 | None | |
34 | -| auth | 로그인 | POST | api/auth/login | 바로가기 | None | | 34 | +| notify | 슬랙 메시지 전송 요청 | POST | api/notify/ | |
35 | -| auth | 로그아웃 | GET | api/auth/logout | 바로가기 | JWT Token | | 35 | +| slack | 바로가기 | Jwt Token | |
36 | -| auth | 회원가입 | POST | api/auth/register | 바로가기 | None | | 36 | +| auth | 로그인 | POST | api/auth/login | 바로가기 | None | |
37 | -| auth | 로그인 확인 | GET | api/auth/check | 바로가기 | None | | 37 | +| auth | 로그아웃 | POST | api/auth/logout | 바로가기 | JWT Token | |
38 | +| auth | 회원가입 | POST | api/auth/register | 바로가기 | None | | ||
39 | +| auth | 로그인 확인 | GET | api/auth/check | 바로가기 | None | | ... | ... |
... | @@ -2,6 +2,8 @@ const Koa = require("koa"); | ... | @@ -2,6 +2,8 @@ const Koa = require("koa"); |
2 | const Router = require("koa-router"); | 2 | const Router = require("koa-router"); |
3 | const bodyParser = require("koa-bodyparser"); | 3 | const bodyParser = require("koa-bodyparser"); |
4 | const mongoose = require("mongoose"); | 4 | const mongoose = require("mongoose"); |
5 | +const fs = require("fs"); | ||
6 | +const morgan = require("koa-morgan"); | ||
5 | const jwtMiddleware = require("./src/lib/jwtMiddleware"); | 7 | const jwtMiddleware = require("./src/lib/jwtMiddleware"); |
6 | const api = require("./src/api"); | 8 | const api = require("./src/api"); |
7 | 9 | ||
... | @@ -9,10 +11,13 @@ require("dotenv").config(); | ... | @@ -9,10 +11,13 @@ require("dotenv").config(); |
9 | 11 | ||
10 | const app = new Koa(); | 12 | const app = new Koa(); |
11 | const router = new Router(); | 13 | const router = new Router(); |
12 | - | 14 | +const accessLogStream = fs.createWriteStream(__dirname + "/access.log", { |
15 | + flags: "a", | ||
16 | +}); | ||
17 | +require("dotenv").config(); | ||
13 | app.use(bodyParser()); | 18 | app.use(bodyParser()); |
14 | app.use(jwtMiddleware); | 19 | app.use(jwtMiddleware); |
15 | - | 20 | +app.use(morgan("combined", { stream: accessLogStream })); |
16 | const { SERVER_PORT, MONGO_URL } = process.env; | 21 | const { SERVER_PORT, MONGO_URL } = process.env; |
17 | 22 | ||
18 | router.use("/api", api.routes()); | 23 | router.use("/api", api.routes()); | ... | ... |
... | @@ -198,11 +198,26 @@ | ... | @@ -198,11 +198,26 @@ |
198 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", | 198 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", |
199 | "dev": true | 199 | "dev": true |
200 | }, | 200 | }, |
201 | + "agent-base": { | ||
202 | + "version": "2.1.1", | ||
203 | + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", | ||
204 | + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", | ||
205 | + "requires": { | ||
206 | + "extend": "~3.0.0", | ||
207 | + "semver": "~5.0.1" | ||
208 | + }, | ||
209 | + "dependencies": { | ||
210 | + "semver": { | ||
211 | + "version": "5.0.3", | ||
212 | + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", | ||
213 | + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" | ||
214 | + } | ||
215 | + } | ||
216 | + }, | ||
201 | "ajv": { | 217 | "ajv": { |
202 | "version": "6.12.2", | 218 | "version": "6.12.2", |
203 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", | 219 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", |
204 | "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", | 220 | "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", |
205 | - "dev": true, | ||
206 | "requires": { | 221 | "requires": { |
207 | "fast-deep-equal": "^3.1.1", | 222 | "fast-deep-equal": "^3.1.1", |
208 | "fast-json-stable-stringify": "^2.0.0", | 223 | "fast-json-stable-stringify": "^2.0.0", |
... | @@ -323,12 +338,45 @@ | ... | @@ -323,12 +338,45 @@ |
323 | "sprintf-js": "~1.0.2" | 338 | "sprintf-js": "~1.0.2" |
324 | } | 339 | } |
325 | }, | 340 | }, |
341 | + "asn1": { | ||
342 | + "version": "0.2.4", | ||
343 | + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", | ||
344 | + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", | ||
345 | + "requires": { | ||
346 | + "safer-buffer": "~2.1.0" | ||
347 | + } | ||
348 | + }, | ||
349 | + "assert-plus": { | ||
350 | + "version": "1.0.0", | ||
351 | + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", | ||
352 | + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" | ||
353 | + }, | ||
326 | "astral-regex": { | 354 | "astral-regex": { |
327 | "version": "1.0.0", | 355 | "version": "1.0.0", |
328 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", | 356 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", |
329 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", | 357 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", |
330 | "dev": true | 358 | "dev": true |
331 | }, | 359 | }, |
360 | + "async": { | ||
361 | + "version": "1.5.2", | ||
362 | + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", | ||
363 | + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" | ||
364 | + }, | ||
365 | + "asynckit": { | ||
366 | + "version": "0.4.0", | ||
367 | + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | ||
368 | + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" | ||
369 | + }, | ||
370 | + "aws-sign2": { | ||
371 | + "version": "0.7.0", | ||
372 | + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", | ||
373 | + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" | ||
374 | + }, | ||
375 | + "aws4": { | ||
376 | + "version": "1.10.0", | ||
377 | + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", | ||
378 | + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" | ||
379 | + }, | ||
332 | "axios": { | 380 | "axios": { |
333 | "version": "0.19.2", | 381 | "version": "0.19.2", |
334 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", | 382 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", |
... | @@ -373,6 +421,14 @@ | ... | @@ -373,6 +421,14 @@ |
373 | "node-pre-gyp": "0.14.0" | 421 | "node-pre-gyp": "0.14.0" |
374 | } | 422 | } |
375 | }, | 423 | }, |
424 | + "bcrypt-pbkdf": { | ||
425 | + "version": "1.0.2", | ||
426 | + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", | ||
427 | + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", | ||
428 | + "requires": { | ||
429 | + "tweetnacl": "^0.14.3" | ||
430 | + } | ||
431 | + }, | ||
376 | "binary-extensions": { | 432 | "binary-extensions": { |
377 | "version": "2.0.0", | 433 | "version": "2.0.0", |
378 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", | 434 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", |
... | @@ -517,6 +573,11 @@ | ... | @@ -517,6 +573,11 @@ |
517 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", | 573 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", |
518 | "dev": true | 574 | "dev": true |
519 | }, | 575 | }, |
576 | + "caseless": { | ||
577 | + "version": "0.12.0", | ||
578 | + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", | ||
579 | + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" | ||
580 | + }, | ||
520 | "chalk": { | 581 | "chalk": { |
521 | "version": "3.0.0", | 582 | "version": "3.0.0", |
522 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", | 583 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", |
... | @@ -670,6 +731,19 @@ | ... | @@ -670,6 +731,19 @@ |
670 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", | 731 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", |
671 | "dev": true | 732 | "dev": true |
672 | }, | 733 | }, |
734 | + "colors": { | ||
735 | + "version": "1.0.3", | ||
736 | + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", | ||
737 | + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" | ||
738 | + }, | ||
739 | + "combined-stream": { | ||
740 | + "version": "1.0.8", | ||
741 | + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | ||
742 | + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", | ||
743 | + "requires": { | ||
744 | + "delayed-stream": "~1.0.0" | ||
745 | + } | ||
746 | + }, | ||
673 | "concat-map": { | 747 | "concat-map": { |
674 | "version": "0.0.1", | 748 | "version": "0.0.1", |
675 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | 749 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", |
... | @@ -752,6 +826,15 @@ | ... | @@ -752,6 +826,15 @@ |
752 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", | 826 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", |
753 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" | 827 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" |
754 | }, | 828 | }, |
829 | + "cron-parser": { | ||
830 | + "version": "2.15.0", | ||
831 | + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.15.0.tgz", | ||
832 | + "integrity": "sha512-rMFkrQw8+oG5OuwjiXesup4KeIlEG/IU82YtG4xyAHbO5jhKmYaHPp/ZNhq9+7TjSJ65E3zV3kQPUbmXSff2/g==", | ||
833 | + "requires": { | ||
834 | + "is-nan": "^1.3.0", | ||
835 | + "moment-timezone": "^0.5.31" | ||
836 | + } | ||
837 | + }, | ||
755 | "cross-spawn": { | 838 | "cross-spawn": { |
756 | "version": "7.0.3", | 839 | "version": "7.0.3", |
757 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", | 840 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", |
... | @@ -785,6 +868,19 @@ | ... | @@ -785,6 +868,19 @@ |
785 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", | 868 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", |
786 | "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" | 869 | "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" |
787 | }, | 870 | }, |
871 | + "cycle": { | ||
872 | + "version": "1.0.3", | ||
873 | + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", | ||
874 | + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" | ||
875 | + }, | ||
876 | + "dashdash": { | ||
877 | + "version": "1.14.1", | ||
878 | + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", | ||
879 | + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", | ||
880 | + "requires": { | ||
881 | + "assert-plus": "^1.0.0" | ||
882 | + } | ||
883 | + }, | ||
788 | "debug": { | 884 | "debug": { |
789 | "version": "2.6.9", | 885 | "version": "2.6.9", |
790 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | 886 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", |
... | @@ -831,6 +927,19 @@ | ... | @@ -831,6 +927,19 @@ |
831 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", | 927 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", |
832 | "dev": true | 928 | "dev": true |
833 | }, | 929 | }, |
930 | + "define-properties": { | ||
931 | + "version": "1.1.3", | ||
932 | + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", | ||
933 | + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", | ||
934 | + "requires": { | ||
935 | + "object-keys": "^1.0.12" | ||
936 | + } | ||
937 | + }, | ||
938 | + "delayed-stream": { | ||
939 | + "version": "1.0.0", | ||
940 | + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | ||
941 | + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" | ||
942 | + }, | ||
834 | "delegates": { | 943 | "delegates": { |
835 | "version": "1.0.0", | 944 | "version": "1.0.0", |
836 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", | 945 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", |
... | @@ -916,6 +1025,15 @@ | ... | @@ -916,6 +1025,15 @@ |
916 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", | 1025 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", |
917 | "dev": true | 1026 | "dev": true |
918 | }, | 1027 | }, |
1028 | + "ecc-jsbn": { | ||
1029 | + "version": "0.1.2", | ||
1030 | + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", | ||
1031 | + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", | ||
1032 | + "requires": { | ||
1033 | + "jsbn": "~0.1.0", | ||
1034 | + "safer-buffer": "^2.1.0" | ||
1035 | + } | ||
1036 | + }, | ||
919 | "ecdsa-sig-formatter": { | 1037 | "ecdsa-sig-formatter": { |
920 | "version": "1.0.11", | 1038 | "version": "1.0.11", |
921 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", | 1039 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", |
... | @@ -1170,6 +1288,16 @@ | ... | @@ -1170,6 +1288,16 @@ |
1170 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", | 1288 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", |
1171 | "dev": true | 1289 | "dev": true |
1172 | }, | 1290 | }, |
1291 | + "eventemitter3": { | ||
1292 | + "version": "1.2.0", | ||
1293 | + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", | ||
1294 | + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=" | ||
1295 | + }, | ||
1296 | + "extend": { | ||
1297 | + "version": "3.0.2", | ||
1298 | + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", | ||
1299 | + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" | ||
1300 | + }, | ||
1173 | "external-editor": { | 1301 | "external-editor": { |
1174 | "version": "3.1.0", | 1302 | "version": "3.1.0", |
1175 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", | 1303 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", |
... | @@ -1181,17 +1309,25 @@ | ... | @@ -1181,17 +1309,25 @@ |
1181 | "tmp": "^0.0.33" | 1309 | "tmp": "^0.0.33" |
1182 | } | 1310 | } |
1183 | }, | 1311 | }, |
1312 | + "extsprintf": { | ||
1313 | + "version": "1.3.0", | ||
1314 | + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", | ||
1315 | + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" | ||
1316 | + }, | ||
1317 | + "eyes": { | ||
1318 | + "version": "0.1.8", | ||
1319 | + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", | ||
1320 | + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" | ||
1321 | + }, | ||
1184 | "fast-deep-equal": { | 1322 | "fast-deep-equal": { |
1185 | "version": "3.1.3", | 1323 | "version": "3.1.3", |
1186 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | 1324 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", |
1187 | - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", | 1325 | + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" |
1188 | - "dev": true | ||
1189 | }, | 1326 | }, |
1190 | "fast-json-stable-stringify": { | 1327 | "fast-json-stable-stringify": { |
1191 | "version": "2.1.0", | 1328 | "version": "2.1.0", |
1192 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", | 1329 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", |
1193 | - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", | 1330 | + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" |
1194 | - "dev": true | ||
1195 | }, | 1331 | }, |
1196 | "fast-levenshtein": { | 1332 | "fast-levenshtein": { |
1197 | "version": "2.0.6", | 1333 | "version": "2.0.6", |
... | @@ -1277,6 +1413,21 @@ | ... | @@ -1277,6 +1413,21 @@ |
1277 | } | 1413 | } |
1278 | } | 1414 | } |
1279 | }, | 1415 | }, |
1416 | + "forever-agent": { | ||
1417 | + "version": "0.6.1", | ||
1418 | + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", | ||
1419 | + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" | ||
1420 | + }, | ||
1421 | + "form-data": { | ||
1422 | + "version": "2.3.3", | ||
1423 | + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", | ||
1424 | + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", | ||
1425 | + "requires": { | ||
1426 | + "asynckit": "^0.4.0", | ||
1427 | + "combined-stream": "^1.0.6", | ||
1428 | + "mime-types": "^2.1.12" | ||
1429 | + } | ||
1430 | + }, | ||
1280 | "fresh": { | 1431 | "fresh": { |
1281 | "version": "0.5.2", | 1432 | "version": "0.5.2", |
1282 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", | 1433 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", |
... | @@ -1367,6 +1518,14 @@ | ... | @@ -1367,6 +1518,14 @@ |
1367 | "pump": "^3.0.0" | 1518 | "pump": "^3.0.0" |
1368 | } | 1519 | } |
1369 | }, | 1520 | }, |
1521 | + "getpass": { | ||
1522 | + "version": "0.1.7", | ||
1523 | + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", | ||
1524 | + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", | ||
1525 | + "requires": { | ||
1526 | + "assert-plus": "^1.0.0" | ||
1527 | + } | ||
1528 | + }, | ||
1370 | "glob": { | 1529 | "glob": { |
1371 | "version": "7.1.6", | 1530 | "version": "7.1.6", |
1372 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", | 1531 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", |
... | @@ -1432,6 +1591,20 @@ | ... | @@ -1432,6 +1591,20 @@ |
1432 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", | 1591 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", |
1433 | "dev": true | 1592 | "dev": true |
1434 | }, | 1593 | }, |
1594 | + "har-schema": { | ||
1595 | + "version": "2.0.0", | ||
1596 | + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", | ||
1597 | + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" | ||
1598 | + }, | ||
1599 | + "har-validator": { | ||
1600 | + "version": "5.1.3", | ||
1601 | + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", | ||
1602 | + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", | ||
1603 | + "requires": { | ||
1604 | + "ajv": "^6.5.5", | ||
1605 | + "har-schema": "^2.0.0" | ||
1606 | + } | ||
1607 | + }, | ||
1435 | "has-flag": { | 1608 | "has-flag": { |
1436 | "version": "3.0.0", | 1609 | "version": "3.0.0", |
1437 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", | 1610 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", |
... | @@ -1513,6 +1686,26 @@ | ... | @@ -1513,6 +1686,26 @@ |
1513 | } | 1686 | } |
1514 | } | 1687 | } |
1515 | }, | 1688 | }, |
1689 | + "http-signature": { | ||
1690 | + "version": "1.2.0", | ||
1691 | + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", | ||
1692 | + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", | ||
1693 | + "requires": { | ||
1694 | + "assert-plus": "^1.0.0", | ||
1695 | + "jsprim": "^1.2.2", | ||
1696 | + "sshpk": "^1.7.0" | ||
1697 | + } | ||
1698 | + }, | ||
1699 | + "https-proxy-agent": { | ||
1700 | + "version": "1.0.0", | ||
1701 | + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", | ||
1702 | + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", | ||
1703 | + "requires": { | ||
1704 | + "agent-base": "2", | ||
1705 | + "debug": "2", | ||
1706 | + "extend": "3" | ||
1707 | + } | ||
1708 | + }, | ||
1516 | "iconv": { | 1709 | "iconv": { |
1517 | "version": "3.0.0", | 1710 | "version": "3.0.0", |
1518 | "resolved": "https://registry.npmjs.org/iconv/-/iconv-3.0.0.tgz", | 1711 | "resolved": "https://registry.npmjs.org/iconv/-/iconv-3.0.0.tgz", |
... | @@ -1669,6 +1862,14 @@ | ... | @@ -1669,6 +1862,14 @@ |
1669 | "is-path-inside": "^3.0.1" | 1862 | "is-path-inside": "^3.0.1" |
1670 | } | 1863 | } |
1671 | }, | 1864 | }, |
1865 | + "is-nan": { | ||
1866 | + "version": "1.3.0", | ||
1867 | + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.0.tgz", | ||
1868 | + "integrity": "sha512-z7bbREymOqt2CCaZVly8aC4ML3Xhfi0ekuOnjO2L8vKdl+CttdVoGZQhd4adMFAsxQ5VeRVwORs4tU8RH+HFtQ==", | ||
1869 | + "requires": { | ||
1870 | + "define-properties": "^1.1.3" | ||
1871 | + } | ||
1872 | + }, | ||
1672 | "is-npm": { | 1873 | "is-npm": { |
1673 | "version": "4.0.0", | 1874 | "version": "4.0.0", |
1674 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", | 1875 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", |
... | @@ -1696,8 +1897,7 @@ | ... | @@ -1696,8 +1897,7 @@ |
1696 | "is-typedarray": { | 1897 | "is-typedarray": { |
1697 | "version": "1.0.0", | 1898 | "version": "1.0.0", |
1698 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", | 1899 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", |
1699 | - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", | 1900 | + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" |
1700 | - "dev": true | ||
1701 | }, | 1901 | }, |
1702 | "is-yarn-global": { | 1902 | "is-yarn-global": { |
1703 | "version": "0.3.0", | 1903 | "version": "0.3.0", |
... | @@ -1724,6 +1924,11 @@ | ... | @@ -1724,6 +1924,11 @@ |
1724 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", | 1924 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", |
1725 | "dev": true | 1925 | "dev": true |
1726 | }, | 1926 | }, |
1927 | + "isstream": { | ||
1928 | + "version": "0.1.2", | ||
1929 | + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", | ||
1930 | + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" | ||
1931 | + }, | ||
1727 | "joi": { | 1932 | "joi": { |
1728 | "version": "14.3.1", | 1933 | "version": "14.3.1", |
1729 | "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", | 1934 | "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", |
... | @@ -1750,6 +1955,11 @@ | ... | @@ -1750,6 +1955,11 @@ |
1750 | "esprima": "^4.0.0" | 1955 | "esprima": "^4.0.0" |
1751 | } | 1956 | } |
1752 | }, | 1957 | }, |
1958 | + "jsbn": { | ||
1959 | + "version": "0.1.1", | ||
1960 | + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", | ||
1961 | + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" | ||
1962 | + }, | ||
1753 | "jsesc": { | 1963 | "jsesc": { |
1754 | "version": "2.5.2", | 1964 | "version": "2.5.2", |
1755 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", | 1965 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", |
... | @@ -1762,11 +1972,15 @@ | ... | @@ -1762,11 +1972,15 @@ |
1762 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", | 1972 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", |
1763 | "dev": true | 1973 | "dev": true |
1764 | }, | 1974 | }, |
1975 | + "json-schema": { | ||
1976 | + "version": "0.2.3", | ||
1977 | + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", | ||
1978 | + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" | ||
1979 | + }, | ||
1765 | "json-schema-traverse": { | 1980 | "json-schema-traverse": { |
1766 | "version": "0.4.1", | 1981 | "version": "0.4.1", |
1767 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | 1982 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", |
1768 | - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", | 1983 | + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" |
1769 | - "dev": true | ||
1770 | }, | 1984 | }, |
1771 | "json-stable-stringify-without-jsonify": { | 1985 | "json-stable-stringify-without-jsonify": { |
1772 | "version": "1.0.1", | 1986 | "version": "1.0.1", |
... | @@ -1774,6 +1988,11 @@ | ... | @@ -1774,6 +1988,11 @@ |
1774 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", | 1988 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", |
1775 | "dev": true | 1989 | "dev": true |
1776 | }, | 1990 | }, |
1991 | + "json-stringify-safe": { | ||
1992 | + "version": "5.0.1", | ||
1993 | + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", | ||
1994 | + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" | ||
1995 | + }, | ||
1777 | "jsonwebtoken": { | 1996 | "jsonwebtoken": { |
1778 | "version": "8.5.1", | 1997 | "version": "8.5.1", |
1779 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", | 1998 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", |
... | @@ -1791,6 +2010,17 @@ | ... | @@ -1791,6 +2010,17 @@ |
1791 | "semver": "^5.6.0" | 2010 | "semver": "^5.6.0" |
1792 | } | 2011 | } |
1793 | }, | 2012 | }, |
2013 | + "jsprim": { | ||
2014 | + "version": "1.4.1", | ||
2015 | + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", | ||
2016 | + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", | ||
2017 | + "requires": { | ||
2018 | + "assert-plus": "1.0.0", | ||
2019 | + "extsprintf": "1.3.0", | ||
2020 | + "json-schema": "0.2.3", | ||
2021 | + "verror": "1.10.0" | ||
2022 | + } | ||
2023 | + }, | ||
1794 | "jwa": { | 2024 | "jwa": { |
1795 | "version": "1.4.1", | 2025 | "version": "1.4.1", |
1796 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", | 2026 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", |
... | @@ -1923,6 +2153,14 @@ | ... | @@ -1923,6 +2153,14 @@ |
1923 | } | 2153 | } |
1924 | } | 2154 | } |
1925 | }, | 2155 | }, |
2156 | + "koa-morgan": { | ||
2157 | + "version": "1.0.1", | ||
2158 | + "resolved": "https://registry.npmjs.org/koa-morgan/-/koa-morgan-1.0.1.tgz", | ||
2159 | + "integrity": "sha1-CAUuDODYOdPEMXi5CluzQkvvH5k=", | ||
2160 | + "requires": { | ||
2161 | + "morgan": "^1.6.1" | ||
2162 | + } | ||
2163 | + }, | ||
1926 | "koa-router": { | 2164 | "koa-router": { |
1927 | "version": "9.0.1", | 2165 | "version": "9.0.1", |
1928 | "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-9.0.1.tgz", | 2166 | "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-9.0.1.tgz", |
... | @@ -2021,6 +2259,11 @@ | ... | @@ -2021,6 +2259,11 @@ |
2021 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", | 2259 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", |
2022 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" | 2260 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" |
2023 | }, | 2261 | }, |
2262 | + "long-timeout": { | ||
2263 | + "version": "0.1.1", | ||
2264 | + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", | ||
2265 | + "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=" | ||
2266 | + }, | ||
2024 | "lowercase-keys": { | 2267 | "lowercase-keys": { |
2025 | "version": "1.0.1", | 2268 | "version": "1.0.1", |
2026 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", | 2269 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", |
... | @@ -2123,6 +2366,19 @@ | ... | @@ -2123,6 +2366,19 @@ |
2123 | "minimist": "^1.2.5" | 2366 | "minimist": "^1.2.5" |
2124 | } | 2367 | } |
2125 | }, | 2368 | }, |
2369 | + "moment": { | ||
2370 | + "version": "2.27.0", | ||
2371 | + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", | ||
2372 | + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" | ||
2373 | + }, | ||
2374 | + "moment-timezone": { | ||
2375 | + "version": "0.5.31", | ||
2376 | + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", | ||
2377 | + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", | ||
2378 | + "requires": { | ||
2379 | + "moment": ">= 2.9.0" | ||
2380 | + } | ||
2381 | + }, | ||
2126 | "mongodb": { | 2382 | "mongodb": { |
2127 | "version": "3.5.8", | 2383 | "version": "3.5.8", |
2128 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.8.tgz", | 2384 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.8.tgz", |
... | @@ -2274,6 +2530,16 @@ | ... | @@ -2274,6 +2530,16 @@ |
2274 | "tar": "^4.4.2" | 2530 | "tar": "^4.4.2" |
2275 | } | 2531 | } |
2276 | }, | 2532 | }, |
2533 | + "node-schedule": { | ||
2534 | + "version": "1.3.2", | ||
2535 | + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.2.tgz", | ||
2536 | + "integrity": "sha512-GIND2pHMHiReSZSvS6dpZcDH7pGPGFfWBIEud6S00Q8zEIzAs9ommdyRK1ZbQt8y1LyZsJYZgPnyi7gpU2lcdw==", | ||
2537 | + "requires": { | ||
2538 | + "cron-parser": "^2.7.3", | ||
2539 | + "long-timeout": "0.1.1", | ||
2540 | + "sorted-array-functions": "^1.0.0" | ||
2541 | + } | ||
2542 | + }, | ||
2277 | "nodemon": { | 2543 | "nodemon": { |
2278 | "version": "2.0.4", | 2544 | "version": "2.0.4", |
2279 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", | 2545 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", |
... | @@ -2371,11 +2637,21 @@ | ... | @@ -2371,11 +2637,21 @@ |
2371 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", | 2637 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", |
2372 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" | 2638 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" |
2373 | }, | 2639 | }, |
2640 | + "oauth-sign": { | ||
2641 | + "version": "0.9.0", | ||
2642 | + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", | ||
2643 | + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" | ||
2644 | + }, | ||
2374 | "object-assign": { | 2645 | "object-assign": { |
2375 | "version": "4.1.1", | 2646 | "version": "4.1.1", |
2376 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | 2647 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", |
2377 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" | 2648 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" |
2378 | }, | 2649 | }, |
2650 | + "object-keys": { | ||
2651 | + "version": "1.1.1", | ||
2652 | + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", | ||
2653 | + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" | ||
2654 | + }, | ||
2379 | "on-finished": { | 2655 | "on-finished": { |
2380 | "version": "2.3.0", | 2656 | "version": "2.3.0", |
2381 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", | 2657 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", |
... | @@ -2425,6 +2701,11 @@ | ... | @@ -2425,6 +2701,11 @@ |
2425 | "word-wrap": "^1.2.3" | 2701 | "word-wrap": "^1.2.3" |
2426 | } | 2702 | } |
2427 | }, | 2703 | }, |
2704 | + "options": { | ||
2705 | + "version": "0.0.6", | ||
2706 | + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", | ||
2707 | + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" | ||
2708 | + }, | ||
2428 | "os-homedir": { | 2709 | "os-homedir": { |
2429 | "version": "1.0.2", | 2710 | "version": "1.0.2", |
2430 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", | 2711 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", |
... | @@ -2518,6 +2799,11 @@ | ... | @@ -2518,6 +2799,11 @@ |
2518 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", | 2799 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", |
2519 | "dev": true | 2800 | "dev": true |
2520 | }, | 2801 | }, |
2802 | + "performance-now": { | ||
2803 | + "version": "2.1.0", | ||
2804 | + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", | ||
2805 | + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" | ||
2806 | + }, | ||
2521 | "picomatch": { | 2807 | "picomatch": { |
2522 | "version": "2.2.2", | 2808 | "version": "2.2.2", |
2523 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", | 2809 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", |
... | @@ -2552,6 +2838,11 @@ | ... | @@ -2552,6 +2838,11 @@ |
2552 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", | 2838 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", |
2553 | "dev": true | 2839 | "dev": true |
2554 | }, | 2840 | }, |
2841 | + "psl": { | ||
2842 | + "version": "1.8.0", | ||
2843 | + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", | ||
2844 | + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" | ||
2845 | + }, | ||
2555 | "pstree.remy": { | 2846 | "pstree.remy": { |
2556 | "version": "1.1.8", | 2847 | "version": "1.1.8", |
2557 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", | 2848 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", |
... | @@ -2668,6 +2959,51 @@ | ... | @@ -2668,6 +2959,51 @@ |
2668 | "rc": "^1.2.8" | 2959 | "rc": "^1.2.8" |
2669 | } | 2960 | } |
2670 | }, | 2961 | }, |
2962 | + "request": { | ||
2963 | + "version": "2.88.2", | ||
2964 | + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", | ||
2965 | + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", | ||
2966 | + "requires": { | ||
2967 | + "aws-sign2": "~0.7.0", | ||
2968 | + "aws4": "^1.8.0", | ||
2969 | + "caseless": "~0.12.0", | ||
2970 | + "combined-stream": "~1.0.6", | ||
2971 | + "extend": "~3.0.2", | ||
2972 | + "forever-agent": "~0.6.1", | ||
2973 | + "form-data": "~2.3.2", | ||
2974 | + "har-validator": "~5.1.3", | ||
2975 | + "http-signature": "~1.2.0", | ||
2976 | + "is-typedarray": "~1.0.0", | ||
2977 | + "isstream": "~0.1.2", | ||
2978 | + "json-stringify-safe": "~5.0.1", | ||
2979 | + "mime-types": "~2.1.19", | ||
2980 | + "oauth-sign": "~0.9.0", | ||
2981 | + "performance-now": "^2.1.0", | ||
2982 | + "qs": "~6.5.2", | ||
2983 | + "safe-buffer": "^5.1.2", | ||
2984 | + "tough-cookie": "~2.5.0", | ||
2985 | + "tunnel-agent": "^0.6.0", | ||
2986 | + "uuid": "^3.3.2" | ||
2987 | + }, | ||
2988 | + "dependencies": { | ||
2989 | + "qs": { | ||
2990 | + "version": "6.5.2", | ||
2991 | + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", | ||
2992 | + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" | ||
2993 | + } | ||
2994 | + } | ||
2995 | + }, | ||
2996 | + "requestretry": { | ||
2997 | + "version": "1.13.0", | ||
2998 | + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", | ||
2999 | + "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", | ||
3000 | + "requires": { | ||
3001 | + "extend": "^3.0.0", | ||
3002 | + "lodash": "^4.15.0", | ||
3003 | + "request": "^2.74.0", | ||
3004 | + "when": "^3.7.7" | ||
3005 | + } | ||
3006 | + }, | ||
2671 | "require_optional": { | 3007 | "require_optional": { |
2672 | "version": "1.0.1", | 3008 | "version": "1.0.1", |
2673 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", | 3009 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", |
... | @@ -2718,6 +3054,11 @@ | ... | @@ -2718,6 +3054,11 @@ |
2718 | "signal-exit": "^3.0.2" | 3054 | "signal-exit": "^3.0.2" |
2719 | } | 3055 | } |
2720 | }, | 3056 | }, |
3057 | + "retry": { | ||
3058 | + "version": "0.8.0", | ||
3059 | + "resolved": "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz", | ||
3060 | + "integrity": "sha1-I2dijcDtskex6rZJ3FOshiisLV8=" | ||
3061 | + }, | ||
2721 | "rimraf": { | 3062 | "rimraf": { |
2722 | "version": "2.7.1", | 3063 | "version": "2.7.1", |
2723 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", | 3064 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", |
... | @@ -2822,6 +3163,38 @@ | ... | @@ -2822,6 +3163,38 @@ |
2822 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", | 3163 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", |
2823 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" | 3164 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" |
2824 | }, | 3165 | }, |
3166 | + "slack-client": { | ||
3167 | + "version": "2.0.6", | ||
3168 | + "resolved": "https://registry.npmjs.org/slack-client/-/slack-client-2.0.6.tgz", | ||
3169 | + "integrity": "sha1-eOuJ9/UnYg4UXM17HY0WvWcLs4M=", | ||
3170 | + "requires": { | ||
3171 | + "async": "^1.5.0", | ||
3172 | + "eventemitter3": "^1.1.1", | ||
3173 | + "https-proxy-agent": "^1.0.0", | ||
3174 | + "inherits": "^2.0.1", | ||
3175 | + "lodash": "^3.10.1", | ||
3176 | + "request": "^2.64.0", | ||
3177 | + "retry": "^0.8.0", | ||
3178 | + "url-join": "0.0.1", | ||
3179 | + "winston": "^2.1.1", | ||
3180 | + "ws": "^1.0.1" | ||
3181 | + }, | ||
3182 | + "dependencies": { | ||
3183 | + "lodash": { | ||
3184 | + "version": "3.10.1", | ||
3185 | + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", | ||
3186 | + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" | ||
3187 | + } | ||
3188 | + } | ||
3189 | + }, | ||
3190 | + "slack-node": { | ||
3191 | + "version": "0.1.8", | ||
3192 | + "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.1.8.tgz", | ||
3193 | + "integrity": "sha1-zamN6GgUhbMB3GdC3cOJcRf600k=", | ||
3194 | + "requires": { | ||
3195 | + "requestretry": "^1.2.2" | ||
3196 | + } | ||
3197 | + }, | ||
2825 | "slice-ansi": { | 3198 | "slice-ansi": { |
2826 | "version": "2.1.0", | 3199 | "version": "2.1.0", |
2827 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", | 3200 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", |
... | @@ -2846,6 +3219,11 @@ | ... | @@ -2846,6 +3219,11 @@ |
2846 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", | 3219 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", |
2847 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" | 3220 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" |
2848 | }, | 3221 | }, |
3222 | + "sorted-array-functions": { | ||
3223 | + "version": "1.2.0", | ||
3224 | + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.2.0.tgz", | ||
3225 | + "integrity": "sha512-sWpjPhIZJtqO77GN+LD8dDsDKcWZ9GCOJNqKzi1tvtjGIzwfoyuRH8S0psunmc6Z5P+qfDqztSbwYR5X/e1UTg==" | ||
3226 | + }, | ||
2849 | "source-map": { | 3227 | "source-map": { |
2850 | "version": "0.5.7", | 3228 | "version": "0.5.7", |
2851 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", | 3229 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", |
... | @@ -2867,6 +3245,27 @@ | ... | @@ -2867,6 +3245,27 @@ |
2867 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", | 3245 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", |
2868 | "dev": true | 3246 | "dev": true |
2869 | }, | 3247 | }, |
3248 | + "sshpk": { | ||
3249 | + "version": "1.16.1", | ||
3250 | + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", | ||
3251 | + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", | ||
3252 | + "requires": { | ||
3253 | + "asn1": "~0.2.3", | ||
3254 | + "assert-plus": "^1.0.0", | ||
3255 | + "bcrypt-pbkdf": "^1.0.0", | ||
3256 | + "dashdash": "^1.12.0", | ||
3257 | + "ecc-jsbn": "~0.1.1", | ||
3258 | + "getpass": "^0.1.1", | ||
3259 | + "jsbn": "~0.1.0", | ||
3260 | + "safer-buffer": "^2.0.2", | ||
3261 | + "tweetnacl": "~0.14.0" | ||
3262 | + } | ||
3263 | + }, | ||
3264 | + "stack-trace": { | ||
3265 | + "version": "0.0.10", | ||
3266 | + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", | ||
3267 | + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" | ||
3268 | + }, | ||
2870 | "statuses": { | 3269 | "statuses": { |
2871 | "version": "1.5.0", | 3270 | "version": "1.5.0", |
2872 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", | 3271 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", |
... | @@ -3070,6 +3469,15 @@ | ... | @@ -3070,6 +3469,15 @@ |
3070 | } | 3469 | } |
3071 | } | 3470 | } |
3072 | }, | 3471 | }, |
3472 | + "tough-cookie": { | ||
3473 | + "version": "2.5.0", | ||
3474 | + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", | ||
3475 | + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", | ||
3476 | + "requires": { | ||
3477 | + "psl": "^1.1.28", | ||
3478 | + "punycode": "^2.1.1" | ||
3479 | + } | ||
3480 | + }, | ||
3073 | "tslib": { | 3481 | "tslib": { |
3074 | "version": "1.13.0", | 3482 | "version": "1.13.0", |
3075 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", | 3483 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", |
... | @@ -3081,6 +3489,19 @@ | ... | @@ -3081,6 +3489,19 @@ |
3081 | "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", | 3489 | "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", |
3082 | "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" | 3490 | "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" |
3083 | }, | 3491 | }, |
3492 | + "tunnel-agent": { | ||
3493 | + "version": "0.6.0", | ||
3494 | + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", | ||
3495 | + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", | ||
3496 | + "requires": { | ||
3497 | + "safe-buffer": "^5.0.1" | ||
3498 | + } | ||
3499 | + }, | ||
3500 | + "tweetnacl": { | ||
3501 | + "version": "0.14.5", | ||
3502 | + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", | ||
3503 | + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" | ||
3504 | + }, | ||
3084 | "type-check": { | 3505 | "type-check": { |
3085 | "version": "0.4.0", | 3506 | "version": "0.4.0", |
3086 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", | 3507 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", |
... | @@ -3114,6 +3535,11 @@ | ... | @@ -3114,6 +3535,11 @@ |
3114 | "is-typedarray": "^1.0.0" | 3535 | "is-typedarray": "^1.0.0" |
3115 | } | 3536 | } |
3116 | }, | 3537 | }, |
3538 | + "ultron": { | ||
3539 | + "version": "1.0.2", | ||
3540 | + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", | ||
3541 | + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" | ||
3542 | + }, | ||
3117 | "undefsafe": { | 3543 | "undefsafe": { |
3118 | "version": "2.0.3", | 3544 | "version": "2.0.3", |
3119 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", | 3545 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", |
... | @@ -3162,11 +3588,15 @@ | ... | @@ -3162,11 +3588,15 @@ |
3162 | "version": "4.2.2", | 3588 | "version": "4.2.2", |
3163 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", | 3589 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", |
3164 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", | 3590 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", |
3165 | - "dev": true, | ||
3166 | "requires": { | 3591 | "requires": { |
3167 | "punycode": "^2.1.0" | 3592 | "punycode": "^2.1.0" |
3168 | } | 3593 | } |
3169 | }, | 3594 | }, |
3595 | + "url-join": { | ||
3596 | + "version": "0.0.1", | ||
3597 | + "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz", | ||
3598 | + "integrity": "sha1-HbSK1CLTQCRpqH99l73r/k+x48g=" | ||
3599 | + }, | ||
3170 | "url-parse-lax": { | 3600 | "url-parse-lax": { |
3171 | "version": "3.0.0", | 3601 | "version": "3.0.0", |
3172 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", | 3602 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", |
... | @@ -3196,6 +3626,11 @@ | ... | @@ -3196,6 +3626,11 @@ |
3196 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | 3626 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", |
3197 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" | 3627 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" |
3198 | }, | 3628 | }, |
3629 | + "uuid": { | ||
3630 | + "version": "3.4.0", | ||
3631 | + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", | ||
3632 | + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" | ||
3633 | + }, | ||
3199 | "v8-compile-cache": { | 3634 | "v8-compile-cache": { |
3200 | "version": "2.1.0", | 3635 | "version": "2.1.0", |
3201 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", | 3636 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", |
... | @@ -3207,11 +3642,26 @@ | ... | @@ -3207,11 +3642,26 @@ |
3207 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", | 3642 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", |
3208 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" | 3643 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" |
3209 | }, | 3644 | }, |
3645 | + "verror": { | ||
3646 | + "version": "1.10.0", | ||
3647 | + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", | ||
3648 | + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", | ||
3649 | + "requires": { | ||
3650 | + "assert-plus": "^1.0.0", | ||
3651 | + "core-util-is": "1.0.2", | ||
3652 | + "extsprintf": "^1.2.0" | ||
3653 | + } | ||
3654 | + }, | ||
3210 | "voca": { | 3655 | "voca": { |
3211 | "version": "1.4.0", | 3656 | "version": "1.4.0", |
3212 | "resolved": "https://registry.npmjs.org/voca/-/voca-1.4.0.tgz", | 3657 | "resolved": "https://registry.npmjs.org/voca/-/voca-1.4.0.tgz", |
3213 | "integrity": "sha512-8Xz4H3vhYRGbFupLtl6dHwMx0ojUcjt0HYkqZ9oBCfipd/5mD7Md58m2/dq7uPuZU/0T3Gb1m66KS9jn+I+14Q==" | 3658 | "integrity": "sha512-8Xz4H3vhYRGbFupLtl6dHwMx0ojUcjt0HYkqZ9oBCfipd/5mD7Md58m2/dq7uPuZU/0T3Gb1m66KS9jn+I+14Q==" |
3214 | }, | 3659 | }, |
3660 | + "when": { | ||
3661 | + "version": "3.7.8", | ||
3662 | + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", | ||
3663 | + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" | ||
3664 | + }, | ||
3215 | "which": { | 3665 | "which": { |
3216 | "version": "2.0.2", | 3666 | "version": "2.0.2", |
3217 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", | 3667 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", |
... | @@ -3267,6 +3717,26 @@ | ... | @@ -3267,6 +3717,26 @@ |
3267 | "string-width": "^4.0.0" | 3717 | "string-width": "^4.0.0" |
3268 | } | 3718 | } |
3269 | }, | 3719 | }, |
3720 | + "winston": { | ||
3721 | + "version": "2.4.5", | ||
3722 | + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", | ||
3723 | + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", | ||
3724 | + "requires": { | ||
3725 | + "async": "~1.0.0", | ||
3726 | + "colors": "1.0.x", | ||
3727 | + "cycle": "1.0.x", | ||
3728 | + "eyes": "0.1.x", | ||
3729 | + "isstream": "0.1.x", | ||
3730 | + "stack-trace": "0.0.x" | ||
3731 | + }, | ||
3732 | + "dependencies": { | ||
3733 | + "async": { | ||
3734 | + "version": "1.0.0", | ||
3735 | + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", | ||
3736 | + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" | ||
3737 | + } | ||
3738 | + } | ||
3739 | + }, | ||
3270 | "word-wrap": { | 3740 | "word-wrap": { |
3271 | "version": "1.2.3", | 3741 | "version": "1.2.3", |
3272 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", | 3742 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", |
... | @@ -3299,6 +3769,15 @@ | ... | @@ -3299,6 +3769,15 @@ |
3299 | "typedarray-to-buffer": "^3.1.5" | 3769 | "typedarray-to-buffer": "^3.1.5" |
3300 | } | 3770 | } |
3301 | }, | 3771 | }, |
3772 | + "ws": { | ||
3773 | + "version": "1.1.5", | ||
3774 | + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", | ||
3775 | + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", | ||
3776 | + "requires": { | ||
3777 | + "options": ">=0.0.5", | ||
3778 | + "ultron": "1.0.x" | ||
3779 | + } | ||
3780 | + }, | ||
3302 | "xdg-basedir": { | 3781 | "xdg-basedir": { |
3303 | "version": "4.0.0", | 3782 | "version": "4.0.0", |
3304 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", | 3783 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", | ... | ... |
... | @@ -17,10 +17,14 @@ | ... | @@ -17,10 +17,14 @@ |
17 | "jsonwebtoken": "^8.5.1", | 17 | "jsonwebtoken": "^8.5.1", |
18 | "koa": "^2.12.0", | 18 | "koa": "^2.12.0", |
19 | "koa-bodyparser": "^4.3.0", | 19 | "koa-bodyparser": "^4.3.0", |
20 | + "koa-morgan": "^1.0.1", | ||
20 | "koa-router": "^9.0.1", | 21 | "koa-router": "^9.0.1", |
21 | "mongoose": "^5.9.17", | 22 | "mongoose": "^5.9.17", |
22 | "morgan": "^1.10.0", | 23 | "morgan": "^1.10.0", |
24 | + "node-schedule": "^1.3.2", | ||
23 | "path": "^0.12.7", | 25 | "path": "^0.12.7", |
26 | + "slack-client": "^2.0.6", | ||
27 | + "slack-node": "^0.1.8", | ||
24 | "voca": "^1.4.0" | 28 | "voca": "^1.4.0" |
25 | }, | 29 | }, |
26 | "devDependencies": { | 30 | "devDependencies": { | ... | ... |
1 | const Joi = require("joi"); | 1 | const Joi = require("joi"); |
2 | const User = require("../../models/user"); | 2 | const User = require("../../models/user"); |
3 | +const Profile = require("../../models/profile"); | ||
3 | /* | 4 | /* |
4 | POST /api/auth/register | 5 | POST /api/auth/register |
5 | { | 6 | { |
... | @@ -27,15 +28,19 @@ exports.register = async (ctx) => { | ... | @@ -27,15 +28,19 @@ exports.register = async (ctx) => { |
27 | ctx.status = 409; | 28 | ctx.status = 409; |
28 | return; | 29 | return; |
29 | } | 30 | } |
31 | + const profile = new Profile({ | ||
32 | + username, | ||
33 | + }); | ||
30 | const user = new User({ | 34 | const user = new User({ |
31 | username, | 35 | username, |
32 | }); | 36 | }); |
33 | await user.setPassword(password); | 37 | await user.setPassword(password); |
38 | + await profile.save(); | ||
34 | await user.save(); | 39 | await user.save(); |
35 | ctx.body = user.serialize(); | 40 | ctx.body = user.serialize(); |
36 | 41 | ||
37 | const token = user.generateToken(); | 42 | const token = user.generateToken(); |
38 | - ctx.cookies.set("acces_token", token, { | 43 | + ctx.cookies.set("access_token", token, { |
39 | //3일동안 유효 | 44 | //3일동안 유효 |
40 | maxAge: 1000 * 60 * 60 * 24 * 3, | 45 | maxAge: 1000 * 60 * 60 * 24 * 3, |
41 | httpOnly: true, | 46 | httpOnly: true, |
... | @@ -70,7 +75,7 @@ exports.login = async (ctx) => { | ... | @@ -70,7 +75,7 @@ exports.login = async (ctx) => { |
70 | } | 75 | } |
71 | ctx.body = user.serialize(); | 76 | ctx.body = user.serialize(); |
72 | const token = user.generateToken(); | 77 | const token = user.generateToken(); |
73 | - ctx.cookies.set("acces_token", token, { | 78 | + ctx.cookies.set("access_token", token, { |
74 | //7일동안 유효 | 79 | //7일동안 유효 |
75 | maxAge: 1000 * 60 * 60 * 24 * 7, | 80 | maxAge: 1000 * 60 * 60 * 24 * 7, |
76 | httpOnly: true, | 81 | httpOnly: true, | ... | ... |
... | @@ -2,7 +2,8 @@ const Router = require("koa-router"); | ... | @@ -2,7 +2,8 @@ const Router = require("koa-router"); |
2 | const auth = new Router(); | 2 | const auth = new Router(); |
3 | const authCtrl = require("./auth.ctrl"); | 3 | const authCtrl = require("./auth.ctrl"); |
4 | auth.post("/login", authCtrl.login); | 4 | auth.post("/login", authCtrl.login); |
5 | -auth.get("/logout", authCtrl.logout); | 5 | +auth.post("/logout", authCtrl.logout); |
6 | auth.post("/register", authCtrl.register); | 6 | auth.post("/register", authCtrl.register); |
7 | +auth.get("/check", authCtrl.check); | ||
7 | 8 | ||
8 | module.exports = auth; | 9 | module.exports = auth; | ... | ... |
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 | 4 | ||
4 | profile.post("/solved:id"); | 5 | profile.post("/solved:id"); |
5 | profile.get("/solvednum:id"); | 6 | profile.get("/solvednum:id"); |
6 | -profile.get("recommendps:id"); | 7 | +profile.get("/recommendps:id"); |
7 | - | 8 | +profile.patch("/syncBJ", profileCtrl.syncBJ); |
9 | +profile.post("/setprofile", profileCtrl.setProfile); | ||
10 | +profile.post("/getprofile", profileCtrl.getProfile); | ||
8 | module.exports = profile; | 11 | module.exports = profile; | ... | ... |
1 | +const Profile = require("../../models/profile"); | ||
2 | +const mongoose = require("mongoose"); | ||
3 | +const getBJ = require("../../util/getBJ"); | ||
4 | +const Joi = require("joi"); | ||
5 | + | ||
6 | +const { ObjectId } = mongoose.Types; | ||
7 | + | ||
8 | +exports.checkObjectId = (ctx, next) => { | ||
9 | + const { username } = ctx.request.body; | ||
10 | + if (!ObjectId.isValid(username)) { | ||
11 | + ctx.status = 400; | ||
12 | + return; | ||
13 | + } | ||
14 | + return next(); | ||
15 | +}; | ||
16 | +/*POST /api/profile/getprofile | ||
17 | +{ | ||
18 | + username: "username" | ||
19 | +} | ||
20 | +*/ | ||
21 | +exports.getProfile = async (ctx) => { | ||
22 | + try { | ||
23 | + const { username } = ctx.request.body; | ||
24 | + const profile = await Profile.findByUsername(username); | ||
25 | + if (!profile) { | ||
26 | + ctx.status = 401; | ||
27 | + return; | ||
28 | + } | ||
29 | + ctx.body = profile; | ||
30 | + } catch (e) { | ||
31 | + ctx.throw(500, e); | ||
32 | + } | ||
33 | +}; | ||
34 | +/* | ||
35 | +POST /api/proflie/setprofile | ||
36 | +{ | ||
37 | + username: "username", | ||
38 | + userBJID: "userBJID", | ||
39 | + friendList: [String], | ||
40 | +} | ||
41 | + */ | ||
42 | +exports.setProfile = async (ctx) => { | ||
43 | + const schema = Joi.object() | ||
44 | + .keys({ | ||
45 | + username: Joi.string(), | ||
46 | + userBJID: Joi.string(), | ||
47 | + //freindList: Joi.array().items(Joi.string()), | ||
48 | + }) | ||
49 | + .unknown(); | ||
50 | + | ||
51 | + const result = Joi.validate(ctx.request.body, schema); | ||
52 | + if (result.error) { | ||
53 | + ctx.status = 400; | ||
54 | + ctx.body = result.error; | ||
55 | + return; | ||
56 | + } | ||
57 | + | ||
58 | + try { | ||
59 | + const profile = await Profile.findOneAndUpdate( | ||
60 | + { username: ctx.request.body.username }, | ||
61 | + ctx.request.body, | ||
62 | + { | ||
63 | + new: true, | ||
64 | + } | ||
65 | + ).exec(); | ||
66 | + | ||
67 | + if (!profile) { | ||
68 | + ctx.status = 404; | ||
69 | + return; | ||
70 | + } | ||
71 | + ctx.body = profile; | ||
72 | + } catch (e) { | ||
73 | + ctx.throw(500, e); | ||
74 | + } | ||
75 | +}; | ||
76 | +/* | ||
77 | +PATCH /api/proflie/syncBJ | ||
78 | +{ | ||
79 | + username: 'userid' | ||
80 | +} | ||
81 | + */ | ||
82 | +exports.syncBJ = async function (ctx) { | ||
83 | + const { username } = ctx.request.body; | ||
84 | + | ||
85 | + if (!username) { | ||
86 | + ctx.status = 401; | ||
87 | + return; | ||
88 | + } | ||
89 | + | ||
90 | + try { | ||
91 | + const profile = await Profile.findByUsername(username); | ||
92 | + if (!profile) { | ||
93 | + ctx.status = 401; | ||
94 | + return; | ||
95 | + } | ||
96 | + const BJID = await profile.getBJID(); | ||
97 | + let BJdata = await getBJ.getBJ(BJID); | ||
98 | + const updateprofile = await Profile.findOneAndUpdate( | ||
99 | + { username: username }, | ||
100 | + { solvedBJ: BJdata }, | ||
101 | + { new: true } | ||
102 | + ).exec(); | ||
103 | + ctx.body = updateprofile; | ||
104 | + } catch (e) { | ||
105 | + ctx.throw(500, e); | ||
106 | + } | ||
107 | +}; |
1 | const jwt = require("jsonwebtoken"); | 1 | const jwt = require("jsonwebtoken"); |
2 | const User = require("../models/user"); | 2 | const User = require("../models/user"); |
3 | + | ||
3 | const jwtMiddleware = async (ctx, next) => { | 4 | const jwtMiddleware = async (ctx, next) => { |
4 | const token = ctx.cookies.get("access_token"); | 5 | const token = ctx.cookies.get("access_token"); |
6 | + | ||
5 | if (!token) { | 7 | if (!token) { |
6 | - //토큰이 없을 때 | ||
7 | return next(); | 8 | return next(); |
8 | } | 9 | } |
9 | try { | 10 | try { |
10 | - const decoded = jwt.verify(token, process.env.JWT_TOKEN); | 11 | + const decoded = jwt.verify(token, process.env.JWT_SECRET); |
11 | ctx.state.user = { | 12 | ctx.state.user = { |
12 | _id: decoded._id, | 13 | _id: decoded._id, |
13 | username: decoded.username, | 14 | username: decoded.username, |
14 | }; | 15 | }; |
15 | - //토큰의 남은 유효 기간이 2일 이하라면 재발급 | 16 | + const now = Math.floor(Date.now() / 1000); |
16 | - if (decoded.exp - Date.now() / 1000 < 60 * 60 * 24 * 2) { | 17 | + if (decoded.exp - now < 60 * 60 * 24 * 3.5) { |
17 | const user = await User.findById(decoded._id); | 18 | const user = await User.findById(decoded._id); |
18 | const token = user.generateToken(); | 19 | const token = user.generateToken(); |
19 | ctx.cookies.set("access_token", token, { | 20 | ctx.cookies.set("access_token", token, { |
20 | - maxAge: 1000 * 60 * 60 * 24 * 7, | 21 | + maxAge: 1000 * 60 * 60 * 24 * 7, //7days |
21 | httpOnly: true, | 22 | httpOnly: true, |
22 | }); | 23 | }); |
23 | } | 24 | } |
25 | + | ||
24 | return next(); | 26 | return next(); |
25 | } catch (e) { | 27 | } catch (e) { |
26 | return next(); | 28 | return next(); |
27 | } | 29 | } |
28 | }; | 30 | }; |
29 | - | ||
30 | module.exports = jwtMiddleware; | 31 | module.exports = jwtMiddleware; | ... | ... |
jaksimsamil-server/src/models/profile.js
0 → 100644
1 | +const mongoose = require("mongoose"); | ||
2 | + | ||
3 | +const { Schema } = mongoose; | ||
4 | + | ||
5 | +const ProfileSchema = new Schema({ | ||
6 | + username: { type: String, required: true, unique: true }, | ||
7 | + userBJID: String, | ||
8 | + solvedBJ: Object, | ||
9 | + friendList: [String], | ||
10 | +}); | ||
11 | +ProfileSchema.statics.findByUsername = function (username) { | ||
12 | + return this.findOne({ username }); | ||
13 | +}; | ||
14 | +ProfileSchema.methods.getBJID = function () { | ||
15 | + return this.userBJID; | ||
16 | +}; | ||
17 | + | ||
18 | +ProfileSchema.methods.serialize = function () { | ||
19 | + const data = this.toJSON(); | ||
20 | + return data; | ||
21 | +}; | ||
22 | +const Profile = mongoose.model("Profile", ProfileSchema); | ||
23 | +module.exports = Profile; |
... | @@ -3,7 +3,6 @@ const cheerio = require("cheerio"); | ... | @@ -3,7 +3,6 @@ const cheerio = require("cheerio"); |
3 | const StringToDate = require("./StringToDate"); | 3 | const StringToDate = require("./StringToDate"); |
4 | /* | 4 | /* |
5 | ToDO | 5 | ToDO |
6 | -- 유저 네임 검증 | ||
7 | - 예외 처리 | 6 | - 예외 처리 |
8 | */ | 7 | */ |
9 | exports.getBJ = async function (userid) { | 8 | exports.getBJ = async function (userid) { | ... | ... |
jaksimsamil-server/src/util/sendSlack.js
0 → 100644
1 | +const Slack = require("slack-node"); // 슬랙 모듈 사용 | ||
2 | + | ||
3 | +const webhookUri = | ||
4 | + "https://hooks.slack.com/services/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"; // Webhook URL | ||
5 | + | ||
6 | +const slack = new Slack(); | ||
7 | +slack.setWebhook(webhookUri); | ||
8 | + | ||
9 | +const send = async (message) => { | ||
10 | + slack.webhook( | ||
11 | + { | ||
12 | + text: message, | ||
13 | + }, | ||
14 | + function (err, response) { | ||
15 | + console.log(response); | ||
16 | + } | ||
17 | + ); | ||
18 | +}; | ||
19 | + | ||
20 | +send("hello"); |
-
Please register or login to post a comment