송용우

Merge commit '38227cf5' into feature/frontend_page

1 +import React from 'react';
2 +import { makeStyles } from '@material-ui/core/styles';
3 +
4 +import Button from '@material-ui/core/Button';
5 +import TextField from '@material-ui/core/TextField';
6 +
7 +const useStyles = makeStyles((theme) => ({
8 + root: {
9 + '& > *': {
10 + margin: theme.spacing(1),
11 + },
12 + },
13 +}));
14 +
15 +const GoalNumForm = ({ onChange, profile, onGoalNumSubmit }) => {
16 + const classes = useStyles();
17 + return (
18 + <div>
19 + <form onSubmit={onGoalNumSubmit}>
20 + <TextField
21 + name="goalNum"
22 + type="number"
23 + onChange={onChange}
24 + value={profile.goalNum}
25 + placeholder="일일 목표"
26 + label="일일 목표"
27 + InputLabelProps={{
28 + shrink: true,
29 + }}
30 + />
31 + <Button variant="outlined" type="submit">
32 + 등록
33 + </Button>
34 + </form>
35 + </div>
36 + );
37 +};
38 +
39 +export default GoalNumForm;
...@@ -2,9 +2,12 @@ import React from 'react'; ...@@ -2,9 +2,12 @@ import React from 'react';
2 import palette from '../../lib/styles/palette'; 2 import palette from '../../lib/styles/palette';
3 import BJIDForm from './BJIDForm'; 3 import BJIDForm from './BJIDForm';
4 import SlackForm from './SlackForm'; 4 import SlackForm from './SlackForm';
5 +import GoalNumForm from './GoalNumForm';
5 import { makeStyles } from '@material-ui/core/styles'; 6 import { makeStyles } from '@material-ui/core/styles';
6 import Paper from '@material-ui/core/Paper'; 7 import Paper from '@material-ui/core/Paper';
7 import Grid from '@material-ui/core/Grid'; 8 import Grid from '@material-ui/core/Grid';
9 +import CircularProgress from '@material-ui/core/CircularProgress';
10 +import styled from 'styled-components';
8 11
9 const useStyles = makeStyles((theme) => ({ 12 const useStyles = makeStyles((theme) => ({
10 root: { 13 root: {
...@@ -18,15 +21,29 @@ const useStyles = makeStyles((theme) => ({ ...@@ -18,15 +21,29 @@ const useStyles = makeStyles((theme) => ({
18 }, 21 },
19 })); 22 }));
20 23
24 +const LoadingParentStyle = styled.div`
25 + display: flex;
26 + flex-direction: column;
27 + justify-content: center;
28 + align-items: center;
29 + padding-top: 20px;
30 +`;
31 +
21 const SettingForm = ({ 32 const SettingForm = ({
22 onChange, 33 onChange,
23 onBJIDSubmit, 34 onBJIDSubmit,
24 onSlackURLSubmit, 35 onSlackURLSubmit,
25 profile, 36 profile,
26 onSyncBJIDSubmit, 37 onSyncBJIDSubmit,
38 + onGoalNumSubmit,
39 + isLoading,
27 }) => { 40 }) => {
28 const classes = useStyles(); 41 const classes = useStyles();
29 - return ( 42 + return isLoading ? (
43 + <LoadingParentStyle>
44 + <CircularProgress className={classes.loading} />
45 + </LoadingParentStyle>
46 + ) : (
30 <div className={classes.root}> 47 <div className={classes.root}>
31 <Grid container spacing={3}> 48 <Grid container spacing={3}>
32 <Grid item xs={12}> 49 <Grid item xs={12}>
...@@ -54,6 +71,16 @@ const SettingForm = ({ ...@@ -54,6 +71,16 @@ const SettingForm = ({
54 /> 71 />
55 </Paper> 72 </Paper>
56 </Grid> 73 </Grid>
74 +
75 + <Grid container item xs={12}>
76 + <Paper className={classes.paper} elevation={3}>
77 + <GoalNumForm
78 + profile={profile}
79 + onChange={onChange}
80 + onGoalNumSubmit={onGoalNumSubmit}
81 + />
82 + </Paper>
83 + </Grid>
57 </Grid> 84 </Grid>
58 </div> 85 </div>
59 ); 86 );
......
...@@ -3,14 +3,15 @@ import { useDispatch, useSelector } from 'react-redux'; ...@@ -3,14 +3,15 @@ import { useDispatch, useSelector } from 'react-redux';
3 import { withRouter } from 'react-router-dom'; 3 import { withRouter } from 'react-router-dom';
4 import HomeForm from '../../components/home/HomeForm'; 4 import HomeForm from '../../components/home/HomeForm';
5 import { getPROFILE } from '../../modules/profile'; 5 import { getPROFILE } from '../../modules/profile';
6 -import { analyzeBJ } from '../../lib/util/analyzeBJ';
7 const HomeContainer = ({ history }) => { 6 const HomeContainer = ({ history }) => {
8 const dispatch = useDispatch(); 7 const dispatch = useDispatch();
9 const { user, profile } = useSelector(({ user, profile }) => ({ 8 const { user, profile } = useSelector(({ user, profile }) => ({
10 user: user.user, 9 user: user.user,
11 profile: profile, 10 profile: profile,
12 })); 11 }));
13 - useEffect(() => {}, [profile.solvedBJ]); 12 + useEffect(() => {
13 + console.log(profile);
14 + }, [profile.solvedBJ]);
14 useEffect(() => { 15 useEffect(() => {
15 if (user) { 16 if (user) {
16 let username = user.username; 17 let username = user.username;
......
1 -import React, { useEffect } from 'react'; 1 +import React, { useEffect, useState } from 'react';
2 import { useDispatch, useSelector } from 'react-redux'; 2 import { useDispatch, useSelector } from 'react-redux';
3 import { withRouter } from 'react-router-dom'; 3 import { withRouter } from 'react-router-dom';
4 import { 4 import {
...@@ -8,15 +8,20 @@ import { ...@@ -8,15 +8,20 @@ import {
8 syncBJID, 8 syncBJID,
9 initializeProfile, 9 initializeProfile,
10 setSLACK, 10 setSLACK,
11 + setGOALNUM,
11 } from '../../modules/profile'; 12 } from '../../modules/profile';
12 import SettingForm from '../../components/setting/SettingForm'; 13 import SettingForm from '../../components/setting/SettingForm';
13 14
14 const SettingContainer = ({ history }) => { 15 const SettingContainer = ({ history }) => {
16 + const [isLoading, setLoading] = useState(false);
15 const dispatch = useDispatch(); 17 const dispatch = useDispatch();
16 - const { user, profile } = useSelector(({ user, profile }) => ({ 18 + const { user, profile, loading } = useSelector(
19 + ({ user, profile, loading }) => ({
17 user: user.user, 20 user: user.user,
18 profile: profile, 21 profile: profile,
19 - })); 22 + loading: loading,
23 + }),
24 + );
20 25
21 const onChange = (e) => { 26 const onChange = (e) => {
22 const { value, name } = e.target; 27 const { value, name } = e.target;
...@@ -33,6 +38,13 @@ const SettingContainer = ({ history }) => { ...@@ -33,6 +38,13 @@ const SettingContainer = ({ history }) => {
33 let username = profile.username; 38 let username = profile.username;
34 dispatch(syncBJID({ username })); 39 dispatch(syncBJID({ username }));
35 }; 40 };
41 +
42 + const onGoalNumSubmit = (e) => {
43 + e.preventDefault();
44 + let username = profile.username;
45 + let goalNum = profile.goalNum;
46 + dispatch(setGOALNUM({ username, goalNum }));
47 + };
36 const onSlackURLSubmit = (e) => { 48 const onSlackURLSubmit = (e) => {
37 e.preventDefault(); 49 e.preventDefault();
38 let username = profile.username; 50 let username = profile.username;
...@@ -60,6 +72,13 @@ const SettingContainer = ({ history }) => { ...@@ -60,6 +72,13 @@ const SettingContainer = ({ history }) => {
60 }; 72 };
61 } 73 }
62 }, [dispatch, user, history]); 74 }, [dispatch, user, history]);
75 + useEffect(() => {
76 + if (loading['profile/SYNC_BJID'] == true) {
77 + setLoading(true);
78 + } else {
79 + setLoading(false);
80 + }
81 + }, [dispatch, loading]);
63 82
64 return ( 83 return (
65 <SettingForm 84 <SettingForm
...@@ -68,7 +87,9 @@ const SettingContainer = ({ history }) => { ...@@ -68,7 +87,9 @@ const SettingContainer = ({ history }) => {
68 onBJIDSubmit={onBJIDSubmit} 87 onBJIDSubmit={onBJIDSubmit}
69 onSyncBJIDSubmit={onSyncBJIDSubmit} 88 onSyncBJIDSubmit={onSyncBJIDSubmit}
70 onSlackURLSubmit={onSlackURLSubmit} 89 onSlackURLSubmit={onSlackURLSubmit}
90 + onGoalNumSubmit={onGoalNumSubmit}
71 profile={profile} 91 profile={profile}
92 + isLoading={isLoading}
72 ></SettingForm> 93 ></SettingForm>
73 ); 94 );
74 }; 95 };
......
...@@ -17,6 +17,11 @@ const [ ...@@ -17,6 +17,11 @@ const [
17 SET_SLACK_FAILURE, 17 SET_SLACK_FAILURE,
18 ] = createRequestActionTypes('/profile/SET_SLACK'); 18 ] = createRequestActionTypes('/profile/SET_SLACK');
19 const [ 19 const [
20 + SET_GOALNUM,
21 + SET_GOALNUM_SUCCESS,
22 + SET_GOALNUM_FAILURE,
23 +] = createRequestActionTypes('/profile/SET_GOALNUM');
24 +const [
20 GET_PROFILE, 25 GET_PROFILE,
21 GET_PROFILE_SUCCESS, 26 GET_PROFILE_SUCCESS,
22 GET_PROFILE_FAILURE, 27 GET_PROFILE_FAILURE,
...@@ -31,6 +36,7 @@ export const initializeProfile = createAction(INITIALIZE); ...@@ -31,6 +36,7 @@ export const initializeProfile = createAction(INITIALIZE);
31 export const syncBJID = createAction(SYNC_BJID, ({ username }) => ({ 36 export const syncBJID = createAction(SYNC_BJID, ({ username }) => ({
32 username, 37 username,
33 })); 38 }));
39 +
34 export const setSLACK = createAction( 40 export const setSLACK = createAction(
35 SET_SLACK, 41 SET_SLACK,
36 ({ username, slackWebHookURL }) => ({ 42 ({ username, slackWebHookURL }) => ({
...@@ -38,6 +44,14 @@ export const setSLACK = createAction( ...@@ -38,6 +44,14 @@ export const setSLACK = createAction(
38 slackWebHookURL, 44 slackWebHookURL,
39 }), 45 }),
40 ); 46 );
47 +
48 +export const setGOALNUM = createAction(
49 + SET_GOALNUM,
50 + ({ username, goalNum }) => ({
51 + username,
52 + goalNum,
53 + }),
54 +);
41 export const setBJID = createAction(SET_BJID, ({ username, userBJID }) => ({ 55 export const setBJID = createAction(SET_BJID, ({ username, userBJID }) => ({
42 username, 56 username,
43 userBJID, 57 userBJID,
...@@ -58,16 +72,21 @@ const initialState = { ...@@ -58,16 +72,21 @@ const initialState = {
58 friendList: [], 72 friendList: [],
59 profileError: '', 73 profileError: '',
60 slackWebHookURL: '', 74 slackWebHookURL: '',
75 + solvedBJ_date: '',
76 + goalNum: '',
61 }; 77 };
62 const getPROFILESaga = createRequestSaga(GET_PROFILE, profileAPI.getPROFILE); 78 const getPROFILESaga = createRequestSaga(GET_PROFILE, profileAPI.getPROFILE);
63 const setBJIDSaga = createRequestSaga(SET_BJID, profileAPI.setBJID); 79 const setBJIDSaga = createRequestSaga(SET_BJID, profileAPI.setBJID);
64 const setSLACKSaga = createRequestSaga(SET_SLACK, profileAPI.setPROFILE); 80 const setSLACKSaga = createRequestSaga(SET_SLACK, profileAPI.setPROFILE);
81 +const setGOALNUMSaga = createRequestSaga(SET_GOALNUM, profileAPI.setPROFILE);
65 const syncBJIDSaga = createRequestSaga(SYNC_BJID, profileAPI.syncBJ); 82 const syncBJIDSaga = createRequestSaga(SYNC_BJID, profileAPI.syncBJ);
83 +
66 export function* profileSaga() { 84 export function* profileSaga() {
67 yield takeLatest(SET_BJID, setBJIDSaga); 85 yield takeLatest(SET_BJID, setBJIDSaga);
68 yield takeLatest(GET_PROFILE, getPROFILESaga); 86 yield takeLatest(GET_PROFILE, getPROFILESaga);
69 yield takeLatest(SYNC_BJID, syncBJIDSaga); 87 yield takeLatest(SYNC_BJID, syncBJIDSaga);
70 yield takeLatest(SET_SLACK, setSLACKSaga); 88 yield takeLatest(SET_SLACK, setSLACKSaga);
89 + yield takeLatest(SET_GOALNUM, setGOALNUMSaga);
71 } 90 }
72 91
73 export default handleActions( 92 export default handleActions(
...@@ -80,7 +99,15 @@ export default handleActions( ...@@ -80,7 +99,15 @@ export default handleActions(
80 [GET_PROFILE_SUCCESS]: ( 99 [GET_PROFILE_SUCCESS]: (
81 state, 100 state,
82 { 101 {
83 - payload: { username, userBJID, solvedBJ, friendList, slackWebHookURL }, 102 + payload: {
103 + username,
104 + userBJID,
105 + solvedBJ,
106 + friendList,
107 + slackWebHookURL,
108 + solvedBJ_date,
109 + goalNum,
110 + },
84 }, 111 },
85 ) => ({ 112 ) => ({
86 ...state, 113 ...state,
...@@ -90,6 +117,8 @@ export default handleActions( ...@@ -90,6 +117,8 @@ export default handleActions(
90 friendList: friendList, 117 friendList: friendList,
91 profileError: null, 118 profileError: null,
92 slackWebHookURL: slackWebHookURL, 119 slackWebHookURL: slackWebHookURL,
120 + solvedBJ_date: solvedBJ_date,
121 + goalNum: goalNum,
93 }), 122 }),
94 [GET_PROFILE_FAILURE]: (state, { payload: error }) => ({ 123 [GET_PROFILE_FAILURE]: (state, { payload: error }) => ({
95 ...state, 124 ...state,
...@@ -114,6 +143,14 @@ export default handleActions( ...@@ -114,6 +143,14 @@ export default handleActions(
114 ...state, 143 ...state,
115 profileError: error, 144 profileError: error,
116 }), 145 }),
146 + [SET_GOALNUM_SUCCESS]: (state, { payload: { goalNum } }) => ({
147 + ...state,
148 + goalNum: goalNum,
149 + }),
150 + [SET_GOALNUM_FAILURE]: (state, { payload: error }) => ({
151 + ...state,
152 + profileError: error,
153 + }),
117 [SYNC_BJID_SUCCESS]: (state, { payload: { solvedBJ } }) => ({ 154 [SYNC_BJID_SUCCESS]: (state, { payload: { solvedBJ } }) => ({
118 ...state, 155 ...state,
119 solvedBJ, 156 solvedBJ,
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
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 |
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
30 | profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | 바로가기 | None | 30 | profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | 바로가기 | None |
31 | profile | 유저 정보 수정 | POST | api/profile/setprofile | 바로가기 | JWT TOKEN | 31 | profile | 유저 정보 수정 | POST | api/profile/setprofile | 바로가기 | JWT TOKEN |
32 | profile | 유저 정보 받아오기 | POST | api/profile/getprofile | 바로가기 | JWT | 32 | profile | 유저 정보 받아오기 | POST | api/profile/getprofile | 바로가기 | JWT |
33 -| profile | 추천 문제 조회 | GET | api/profile/recommend:id | 바로가기 | None | 33 +| profile | 추천 문제 조회 | POST | api/profile/recommend | 바로가기 | None |
34 -| notify | 슬랙 메시지 전송 요청 | POST | api/notify/ | 34 +| notify | 슬랙 메시지 전송 요청 (성취여부) | POST | api/notify/goal | 바로가기 | Jwt Token |
35 -| slack | 바로가기 | Jwt Token | 35 +| notify | 슬랙 메시지 전송 요청 (문제 추천) | POST | api/notify/recommend | 바로가기 | None |
36 | auth | 로그인 | POST | api/auth/login | 바로가기 | None | 36 | auth | 로그인 | POST | api/auth/login | 바로가기 | None |
37 | auth | 로그아웃 | POST | api/auth/logout | 바로가기 | JWT Token | 37 | auth | 로그아웃 | POST | api/auth/logout | 바로가기 | JWT Token |
38 | auth | 회원가입 | POST | api/auth/register | 바로가기 | None | 38 | auth | 회원가입 | POST | api/auth/register | 바로가기 | None |
......
This diff is collapsed. Click to expand it.
...@@ -3,7 +3,7 @@ const api = new Router(); ...@@ -3,7 +3,7 @@ const api = new Router();
3 3
4 const auth = require("./auth"); 4 const auth = require("./auth");
5 const friend = require("./friend"); 5 const friend = require("./friend");
6 -const notify = require("./profile"); 6 +const notify = require("./notify");
7 const user = require("./user"); 7 const user = require("./user");
8 const profile = require("./profile"); 8 const profile = require("./profile");
9 9
......
1 const Router = require("koa-router"); 1 const Router = require("koa-router");
2 const notify = new Router(); 2 const notify = new Router();
3 - 3 +const slackCtrl = require("./slack.ctrl");
4 -notify.post("/slack"); 4 +notify.post("/slack/goal", slackCtrl.slackGoal);
5 +notify.post("/slack/recommend", slackCtrl.slackRecommend);
5 6
6 module.exports = notify; 7 module.exports = notify;
......
1 +const Profile = require("../../models/profile");
2 +const sendSlack = require("../../util/sendSlack");
3 +const problem_set = require("../../data/problem_set");
4 +const compareBJ = require("../../util/compareBJ");
5 +/*
6 +POST api/notify/slack/goal
7 +{
8 + username: "username"
9 +}
10 +*/
11 +exports.slackGoal = async (ctx) => {
12 + try {
13 + const { username } = ctx.request.body;
14 +
15 + const profile = await Profile.findByUsername(username);
16 + if (!profile) {
17 + ctx.status = 401;
18 + return;
19 + }
20 + let slackURL = profile.getslackURL();
21 + if (!slackURL) {
22 + ctx.status = 401;
23 + return;
24 + }
25 + let goalNum = profile.getgoalNum();
26 + let todayNum = profile.getTodaySovled();
27 + let message = "";
28 + if (goalNum < todayNum) {
29 + message =
30 + "오늘의 목표 " +
31 + goalNum +
32 + "문제 중 " +
33 + todayNum +
34 + "문제를 풀었습니다." +
35 + "\n" +
36 + "잘하셨습니다!";
37 + } else {
38 + message =
39 + "오늘의 목표 " +
40 + goalNum +
41 + "문제 중 " +
42 + todayNum +
43 + "문제를 풀었습니다." +
44 + "\n" +
45 + "분발하세요!";
46 + }
47 +
48 + sendSlack.send(message, slackURL);
49 + } catch (e) {
50 + ctx.throw(500, e);
51 + }
52 +};
53 +
54 +/*
55 +POST api/notify/slack/recommend
56 +{
57 + username: "username"
58 +}
59 +*/
60 +exports.slackRecommend = async (ctx) => {
61 + try {
62 + console.log("1");
63 + const { username } = ctx.request.body;
64 +
65 + const profile = await Profile.findByUsername(username);
66 + if (!profile) {
67 + ctx.status = 401;
68 + return;
69 + }
70 + let slackURL = profile.getslackURL();
71 + if (!slackURL) {
72 + ctx.status = 401;
73 + return;
74 + }
75 + let unsolved_data = compareBJ.compareBJ(
76 + profile.getBJdata(),
77 + problem_set.problem_set
78 + );
79 + let recommendData = compareBJ.randomItem(unsolved_data);
80 +
81 + if (!recommendData) {
82 + ctx.status = 401;
83 + return;
84 + }
85 + let message =
86 + "오늘의 추천 문제는 " +
87 + recommendData.problem_number +
88 + "번 " +
89 + " <https://www.boj.kr/" +
90 + recommendData.problem_number +
91 + "|" +
92 + recommendData.problem_title +
93 + ">" +
94 + " 입니다.";
95 + sendSlack.send(message, slackURL);
96 + } catch (e) {
97 + ctx.throw(500, e);
98 + }
99 +};
1 const Router = require("koa-router"); 1 const Router = require("koa-router");
2 const profile = new Router(); 2 const profile = new Router();
3 const profileCtrl = require("./profile.ctrl"); 3 const profileCtrl = require("./profile.ctrl");
4 -
5 profile.post("/solved:id"); 4 profile.post("/solved:id");
6 profile.get("/solvednum:id"); 5 profile.get("/solvednum:id");
7 -profile.get("/recommendps:id"); 6 +profile.post("/recommend", profileCtrl.recommend);
8 profile.patch("/syncBJ", profileCtrl.syncBJ); 7 profile.patch("/syncBJ", profileCtrl.syncBJ);
9 profile.post("/setprofile", profileCtrl.setProfile); 8 profile.post("/setprofile", profileCtrl.setProfile);
10 profile.post("/getprofile", profileCtrl.getProfile); 9 profile.post("/getprofile", profileCtrl.getProfile);
......
...@@ -2,6 +2,9 @@ const Profile = require("../../models/profile"); ...@@ -2,6 +2,9 @@ const Profile = require("../../models/profile");
2 const mongoose = require("mongoose"); 2 const mongoose = require("mongoose");
3 const getBJ = require("../../util/getBJ"); 3 const getBJ = require("../../util/getBJ");
4 const Joi = require("joi"); 4 const Joi = require("joi");
5 +const analyzeBJ = require("../../util/analyzeBJ");
6 +const compareBJ = require("../../util/compareBJ");
7 +const problem_set = require("../../data/problem_set");
5 8
6 const { ObjectId } = mongoose.Types; 9 const { ObjectId } = mongoose.Types;
7 10
...@@ -47,7 +50,7 @@ exports.setProfile = async (ctx) => { ...@@ -47,7 +50,7 @@ exports.setProfile = async (ctx) => {
47 //freindList: Joi.array().items(Joi.string()), 50 //freindList: Joi.array().items(Joi.string()),
48 }) 51 })
49 .unknown(); 52 .unknown();
50 - 53 + console.log(ctx.request.body);
51 const result = Joi.validate(ctx.request.body, schema); 54 const result = Joi.validate(ctx.request.body, schema);
52 if (result.error) { 55 if (result.error) {
53 ctx.status = 400; 56 ctx.status = 400;
...@@ -95,9 +98,10 @@ exports.syncBJ = async function (ctx) { ...@@ -95,9 +98,10 @@ exports.syncBJ = async function (ctx) {
95 } 98 }
96 const BJID = await profile.getBJID(); 99 const BJID = await profile.getBJID();
97 let BJdata = await getBJ.getBJ(BJID); 100 let BJdata = await getBJ.getBJ(BJID);
101 + let BJdata_date = await analyzeBJ.analyzeBJ(BJdata);
98 const updateprofile = await Profile.findOneAndUpdate( 102 const updateprofile = await Profile.findOneAndUpdate(
99 { username: username }, 103 { username: username },
100 - { solvedBJ: BJdata }, 104 + { solvedBJ: BJdata, solvedBJ_date: BJdata_date },
101 { new: true } 105 { new: true }
102 ).exec(); 106 ).exec();
103 ctx.body = updateprofile; 107 ctx.body = updateprofile;
...@@ -105,3 +109,33 @@ exports.syncBJ = async function (ctx) { ...@@ -105,3 +109,33 @@ exports.syncBJ = async function (ctx) {
105 ctx.throw(500, e); 109 ctx.throw(500, e);
106 } 110 }
107 }; 111 };
112 +
113 +/*
114 +POST /api/proflie/recommend
115 +{
116 + username: 'userid'
117 +}
118 + */
119 +exports.recommend = async (ctx) => {
120 + const { username } = ctx.request.body;
121 +
122 + if (!username) {
123 + ctx.status = 401;
124 + return;
125 + }
126 + try {
127 + const profile = await Profile.findByUsername(username);
128 + if (!profile) {
129 + ctx.status = 401;
130 + return;
131 + }
132 + let unsolved_data = compareBJ.compareBJ(
133 + profile.getBJdata(),
134 + problem_set.problem_set
135 + );
136 + ctx.body = compareBJ.randomItem(unsolved_data);
137 + //데이터가 비었을 떄 예외처리 필요
138 + } catch (e) {
139 + ctx.throw(500, e);
140 + }
141 +};
......
This diff is collapsed. Click to expand it.
...@@ -6,8 +6,10 @@ const ProfileSchema = new Schema({ ...@@ -6,8 +6,10 @@ const ProfileSchema = new Schema({
6 username: { type: String, required: true, unique: true }, 6 username: { type: String, required: true, unique: true },
7 userBJID: String, 7 userBJID: String,
8 solvedBJ: Object, 8 solvedBJ: Object,
9 + solvedBJ_date: Object,
9 friendList: [String], 10 friendList: [String],
10 slackWebHookURL: String, 11 slackWebHookURL: String,
12 + goalNum: Number,
11 }); 13 });
12 ProfileSchema.statics.findByUsername = function (username) { 14 ProfileSchema.statics.findByUsername = function (username) {
13 return this.findOne({ username }); 15 return this.findOne({ username });
...@@ -15,6 +17,20 @@ ProfileSchema.statics.findByUsername = function (username) { ...@@ -15,6 +17,20 @@ ProfileSchema.statics.findByUsername = function (username) {
15 ProfileSchema.methods.getBJID = function () { 17 ProfileSchema.methods.getBJID = function () {
16 return this.userBJID; 18 return this.userBJID;
17 }; 19 };
20 +ProfileSchema.methods.getBJdata = function () {
21 + return this.solvedBJ;
22 +};
23 +ProfileSchema.methods.getslackURL = function () {
24 + return this.slackWebHookURL;
25 +};
26 +ProfileSchema.methods.getgoalNum = function () {
27 + return this.goalNum;
28 +};
29 +ProfileSchema.methods.getTodaySovled = function () {
30 + if (this.solvedBJ_date) {
31 + return this.solvedBJ_date.presentNum;
32 + }
33 +};
18 34
19 ProfileSchema.methods.serialize = function () { 35 ProfileSchema.methods.serialize = function () {
20 const data = this.toJSON(); 36 const data = this.toJSON();
......
1 -/* 1 +let moment = require("moment");
2 -2. 현재 날짜와의 차이 =>
3 -3. 오늘 푼 문제 => 앞에서부터 순회하면서 데이트 같은거 찾기
4 -3. 최근 일주일간 푼 문제 수 => 앞에서부터 순회하면서 - 값이
5 -4. 추천 문제 => 정규 셋에서 없는거 찾기
6 -5. 날짜별로 묶기.
7 -데이터베이스에서 처리하자
8 -*/
9 -
10 -let moment = require('moment');
11 2
12 exports.analyzeBJ = function (solvedBJ) { 3 exports.analyzeBJ = function (solvedBJ) {
13 try { 4 try {
14 if (solvedBJ) { 5 if (solvedBJ) {
15 - console.log(solvedBJ[0]);
16 let presentDate = moment(); 6 let presentDate = moment();
17 - let presentDate_str = presentDate.format('YYYYMMDD'); 7 + let presentDate_str = presentDate.format("YYYYMMDD");
18 - let latestDate = moment(solvedBJ[0].solved_date, 'YYYYMMDD'); 8 + let latestDate = moment(solvedBJ[0].solved_date, "YYYYMMDD");
19 - let difflatest = presentDate.diff(latestDate, 'days'); 9 + let difflatest = presentDate.diff(latestDate, "days");
20 10
21 let solvedBJbyDATE = {}; 11 let solvedBJbyDATE = {};
22 for (let i = 0; i < solvedBJ.length; i++) { 12 for (let i = 0; i < solvedBJ.length; i++) {
...@@ -34,13 +24,13 @@ exports.analyzeBJ = function (solvedBJ) { ...@@ -34,13 +24,13 @@ exports.analyzeBJ = function (solvedBJ) {
34 ? solvedBJbyDATE[presentDate_str].length 24 ? solvedBJbyDATE[presentDate_str].length
35 : 0; 25 : 0;
36 let returnOBJ = { 26 let returnOBJ = {
37 - latestDate: latestDate.format('YYYYMMDD'), 27 + latestDate: latestDate.format("YYYYMMDD"),
38 difflatest: difflatest, 28 difflatest: difflatest,
39 latestNum: latestNum, 29 latestNum: latestNum,
40 presentNum: presentNum, 30 presentNum: presentNum,
41 solvedBJbyDATE: solvedBJbyDATE, 31 solvedBJbyDATE: solvedBJbyDATE,
42 }; 32 };
43 - console.log(returnOBJ); 33 +
44 return returnOBJ; 34 return returnOBJ;
45 } 35 }
46 } catch (e) { 36 } catch (e) {
......
1 -/*
2 -집중을 해보자.
3 -새거와 데이터가 있다.
4 -데이터 기준으로 새거에 자료가 있으면 넘어가기
5 -없으면 새 배열에 추가
6 -키만 모아둔 리스트를 만들자.
7 -그렇게 해서
8 -반복은 새거 길이만큼
9 -데이터에 있으면 추가 X
10 -없으면 추가
11 -그렇게 반환
12 -*/
13 -
14 exports.compareBJ = function (solvedBJ_new, problem_set) { 1 exports.compareBJ = function (solvedBJ_new, problem_set) {
15 try { 2 try {
16 let new_obj = []; 3 let new_obj = [];
17 - for (let i = 0; i < solvedBJ.length; i++) { 4 +
18 - if (solvedBJ_new[i].problem_number in problem_set) { 5 + for (let i = 0; i < problem_set.length; i++) {
19 - new_obj.push(solvedBJ_new[i]); 6 + let found = false;
7 + for (let j = 0; j < solvedBJ_new.length; j++) {
8 + if (solvedBJ_new[j].problem_number == problem_set[i].problem_number) {
9 + found = true;
10 + break;
11 + }
12 + }
13 + if (!found) {
14 + new_obj.push(problem_set[i]);
20 } 15 }
21 } 16 }
22 console.log(new_obj); 17 console.log(new_obj);
18 + return new_obj;
23 } catch (e) { 19 } catch (e) {
24 console.log(e); 20 console.log(e);
25 } 21 }
26 }; 22 };
23 +
24 +exports.randomItem = function (a) {
25 + return a[Math.floor(Math.random() * a.length)];
26 +};
......
1 const Slack = require("slack-node"); // 슬랙 모듈 사용 1 const Slack = require("slack-node"); // 슬랙 모듈 사용
2 2
3 +/*
3 const webhookUri = 4 const webhookUri =
4 - "https://hooks.slack.com/services/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"; // Webhook URL 5 + "https://hooks.slack.com/services/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"; // Webhook URL
6 +*/
5 7
6 -const slack = new Slack(); 8 +exports.send = async (message, webhookUri) => {
7 -slack.setWebhook(webhookUri); 9 + const slack = new Slack();
8 - 10 + slack.setWebhook(webhookUri);
9 -const send = async (message) => {
10 slack.webhook( 11 slack.webhook(
11 { 12 {
12 text: message, 13 text: message,
...@@ -16,5 +17,3 @@ const send = async (message) => { ...@@ -16,5 +17,3 @@ const send = async (message) => {
16 } 17 }
17 ); 18 );
18 }; 19 };
19 -
20 -send("hello");
......
1 var getBJ = require("./getBJ"); 1 var getBJ = require("./getBJ");
2 var fs = require("fs"); 2 var fs = require("fs");
3 3
4 -let dataset = [
5 - "1517",
6 - "2448",
7 - "1891",
8 - "1074",
9 - "2263",
10 - "1780",
11 - "11728",
12 - "10816",
13 - "10815",
14 - "2109",
15 - "1202",
16 - "1285",
17 - "2138",
18 - "1080",
19 - "11399",
20 - "1931",
21 - "11047",
22 - "15666",
23 - "15665",
24 - "15664",
25 - "15663",
26 - "15657",
27 - "15656",
28 - "15655",
29 - "15654",
30 - "15652",
31 - "15651",
32 - "15650",
33 - "15649",
34 - "6603",
35 - "10971",
36 - "10819",
37 - "10973",
38 - "10974",
39 - "10972",
40 - "7576",
41 - "1248",
42 - "2529",
43 - "15661",
44 - "14501",
45 - "1759",
46 - "14391",
47 - "14889",
48 - "1182",
49 - "11723",
50 - "1748",
51 - "6064",
52 - "1107",
53 - "3085",
54 - "2309",
55 - "1748",
56 - "14500",
57 - "1107",
58 - "1476",
59 - "3085",
60 - "2309",
61 - "1261",
62 - "13549",
63 - "14226",
64 - "13913",
65 - "1697",
66 - "1967",
67 - "1167",
68 - "11725",
69 - "2250",
70 - "1991",
71 - "7562",
72 - "2178",
73 - "4963",
74 - "2667",
75 - "1707",
76 - "11724",
77 - "1260",
78 - "13023",
79 - "11652",
80 - "1377",
81 - "11004",
82 - "10825",
83 - "2751",
84 - "9461",
85 - "1699",
86 - "9095",
87 - "2225",
88 - "2133",
89 - "11727",
90 - "11726",
91 - "1463",
92 - "2748",
93 - "2747",
94 - "11656",
95 - "10824",
96 - "2743",
97 - "10820",
98 - "10808",
99 - "11655",
100 - "11720",
101 - "1008",
102 - "10951",
103 - "2557",
104 - "1021",
105 - "1966",
106 - "2164",
107 - "10799",
108 - "17413",
109 - "10866",
110 - "1158",
111 - "10845",
112 - "1406",
113 - "1874",
114 - "9012",
115 - "9093",
116 - "10828",
117 - "11721",
118 - "11719",
119 - "11718",
120 - "10953",
121 - "2558",
122 - "10814",
123 - "1181",
124 - "11651",
125 - "11650",
126 - "1427",
127 - "2108",
128 - "10989",
129 - "2751",
130 - "2750",
131 - "1436",
132 - "1018",
133 - "7568",
134 - "2231",
135 - "2798",
136 - "1002",
137 - "3053",
138 - "4153",
139 - "3009",
140 - "1085",
141 - "9020",
142 - "4948",
143 - "1929",
144 - "2581",
145 - "1978",
146 - "2292",
147 - "6064",
148 - "2775",
149 - "10250",
150 - "2869",
151 - "1011",
152 - "1193",
153 - "2839",
154 - "1712",
155 - "1316",
156 - "2941",
157 - "5622",
158 - "2908",
159 - "1152",
160 - "1157",
161 - "2675",
162 - "10809",
163 - "11720",
164 - "11654",
165 - "11729",
166 - "2447",
167 - "3052",
168 - "10818",
169 - "10872",
170 - "10870",
171 - "1065",
172 - "4673",
173 - "15596",
174 - "4344",
175 - "2920",
176 - "8958",
177 - "1546",
178 - "2577",
179 - "2562",
180 - "1110",
181 - "10951",
182 - "10952",
183 - "10871",
184 - "2439",
185 - "2438",
186 - "11022",
187 - "11021",
188 - "2742",
189 - "2741",
190 - "15552",
191 - "8393",
192 - "10950",
193 - "2739",
194 - "10817",
195 - "2884",
196 - "2753",
197 - "9498",
198 - "1330",
199 - "2588",
200 - "10430",
201 - "10869",
202 - "1008",
203 - "10998",
204 - "7287",
205 - "10172",
206 - "10171",
207 - "10718",
208 - "1001",
209 - "1000",
210 - "2557",
211 -];
212 -
213 const test = async (userid) => { 4 const test = async (userid) => {
214 let lst = await getBJ.getBJ(userid); 5 let lst = await getBJ.getBJ(userid);
215 let return_lst = []; 6 let return_lst = [];
...@@ -217,7 +8,7 @@ const test = async (userid) => { ...@@ -217,7 +8,7 @@ const test = async (userid) => {
217 return_lst.push(lst[i].problem_number); 8 return_lst.push(lst[i].problem_number);
218 } 9 }
219 10
220 - var stringJson = JSON.stringify(return_lst) + "\n"; 11 + var stringJson = JSON.stringify(lst) + "\n";
221 fs.open("test.json", "a", "666", function (err, id) { 12 fs.open("test.json", "a", "666", function (err, id) {
222 if (err) { 13 if (err) {
223 console.log("file open err!!"); 14 console.log("file open err!!");
......
This diff is collapsed. Click to expand it.