Showing
22 changed files
with
619 additions
and
140 deletions
jaksimsamil-crawler/.gitignore
0 → 100644
jaksimsamil-crawler/README.md
0 → 100644
1 | +# Jaksimsamil Crawler Documentation | ||
2 | + | ||
3 | +## Overview | ||
4 | +- https://acmicpc.net와 https://solved.ac에서 사용자와 문제정보를 크롤링합니다. | ||
5 | +- Python 3.8.3, Pip 20.2.1 환경에서 개발되었습니다. | ||
6 | + | ||
7 | +## Usuage | ||
8 | + | ||
9 | +- Install | ||
10 | +```bash | ||
11 | +pip install -r requirements.txt | ||
12 | +``` | ||
13 | + | ||
14 | +- Run | ||
15 | +```bash | ||
16 | +python main.py | ||
17 | +``` |
jaksimsamil-crawler/main.py
0 → 100644
1 | +import requests | ||
2 | +from bs4 import BeautifulSoup | ||
3 | +import pandas as pd | ||
4 | +from dotenv import load_dotenv | ||
5 | +import sys | ||
6 | +import pymongo | ||
7 | +import os | ||
8 | +from datetime import datetime | ||
9 | +import json | ||
10 | +import numpy as np | ||
11 | + | ||
12 | +SAVE_EVERY=10 | ||
13 | +SAVE_PATH='problems.csv' | ||
14 | +def setup(): | ||
15 | + try: | ||
16 | + load_dotenv(dotenv_path='../jaksimsamil-server/.env') | ||
17 | + client=pymongo.MongoClient('/'.join(os.getenv('MONGO_URL').split('/')[:-1])) | ||
18 | + print('MongoDB Connected') | ||
19 | + return client | ||
20 | + except FileNotFoundError: | ||
21 | + print('.env is not found',file=sys.stderr) | ||
22 | + exit(1) | ||
23 | + | ||
24 | +def save(df,path='problems.csv'): | ||
25 | + print('Saving to {}...'.format(path),end='') | ||
26 | + df.to_csv(path) | ||
27 | + print('Done.') | ||
28 | + | ||
29 | +def load(path='problems.csv'): | ||
30 | + problems=pd.read_csv(path,index_col=0) | ||
31 | + return problems | ||
32 | + | ||
33 | +def get_khu_problem_list(): | ||
34 | + pageNum=1 | ||
35 | + idx=0 | ||
36 | + problems=pd.DataFrame(columns=['problemNum','problemTitle','solvedacLevel','submitNum','correctNum','category','count']) | ||
37 | + while True: | ||
38 | + res=requests.get('https://www.acmicpc.net/school/ranklist/211/{}'.format(pageNum)) | ||
39 | + status_code=res.status_code | ||
40 | + if status_code==404: | ||
41 | + break | ||
42 | + soup=BeautifulSoup(res.text,'html.parser') | ||
43 | + userlinks=soup.select('#ranklist > tbody > tr > td:nth-child(2) > a') | ||
44 | + for userlink in userlinks: | ||
45 | + href=userlink['href'] | ||
46 | + res=requests.get('https://acmicpc.net'+href) | ||
47 | + print('Collecting user data...:',href.split('/')[-1]) | ||
48 | + user_soup=BeautifulSoup(res.text,'html.parser') | ||
49 | + problemNums=user_soup.select('body > div.wrapper > div.container.content > div.row > div:nth-child(2) > div:nth-child(3) > div.col-md-9 > div:nth-child(1) > div.panel-body > span.problem_number') | ||
50 | + for problemNum in problemNums: | ||
51 | + if not problemNum.text in problems['problemNum'].tolist(): | ||
52 | + problems=problems.append({'problemNum':problemNum.text,'count':1},ignore_index=True) | ||
53 | + else: | ||
54 | + problems.loc[problems.problemNum==problemNum.text,'count']=problems.loc[problems.problemNum==problemNum.text,'count']+1 | ||
55 | + if idx%SAVE_EVERY==0: | ||
56 | + save(problems,SAVE_PATH) | ||
57 | + idx+=1 | ||
58 | + pageNum+=1 | ||
59 | + save(problems,SAVE_PATH) | ||
60 | + return problems | ||
61 | + | ||
62 | +def get_problem_info(problems): | ||
63 | + for idx,problemNum in enumerate(problems['problemNum'].values): | ||
64 | + res=requests.get('https://acmicpc.net/problem/{}'.format(problemNum)) | ||
65 | + print('Collecting problem data...:',problemNum) | ||
66 | + soup=BeautifulSoup(res.text,'html.parser') | ||
67 | + problemTitle=soup.select('#problem_title')[0].text | ||
68 | + soup=soup.select('#problem-info > tbody > tr > td') | ||
69 | + submitNum=soup[2].text | ||
70 | + correctNum=soup[4].text | ||
71 | + problems.loc[problems.problemNum==problemNum,'problemTitle']=problemTitle | ||
72 | + problems.loc[problems.problemNum==problemNum,'submitNum']=submitNum | ||
73 | + problems.loc[problems.problemNum==problemNum,'correctNum']=correctNum | ||
74 | + if idx%SAVE_EVERY==0: | ||
75 | + save(problems,SAVE_PATH) | ||
76 | + save(problems,SAVE_PATH) | ||
77 | + return problems | ||
78 | + | ||
79 | +def get_solvedac_level(problems): | ||
80 | + for idx,problemNum in enumerate(problems['problemNum'].values): | ||
81 | + res=requests.get('https://api.solved.ac/v2/search/problems.json?query={}&page=1&sort=id&sort_direction=ascending'.format(problemNum)) | ||
82 | + print('Collecting solved.ac level data...:',problemNum) | ||
83 | + result=json.loads(res.text) | ||
84 | + for problem in result['result']['problems']: | ||
85 | + if int(problem['id'])==int(problemNum): | ||
86 | + problems.loc[problems.problemNum==problemNum,'solvedacLevel']=problem['level'] | ||
87 | + break | ||
88 | + if idx%SAVE_EVERY==0: | ||
89 | + save(problems,SAVE_PATH) | ||
90 | + save(problems,SAVE_PATH) | ||
91 | + return problems | ||
92 | + | ||
93 | +def get_category(problems): | ||
94 | + problems.sort_values(['problemNum'],inplace=True,ignore_index=True) | ||
95 | + problems['category']=problems['category'].fillna(json.dumps([])) | ||
96 | + pageNum=1 | ||
97 | + res=requests.get('https://api.solved.ac/v2/tags/stats.json?page={}'.format(pageNum)) | ||
98 | + tagsResult=json.loads(res.text) | ||
99 | + totalPages=tagsResult['result']['total_page'] | ||
100 | + tags=[] | ||
101 | + tags.extend(tagsResult['result']['tags']) | ||
102 | + for pageNum in range(2,totalPages+1): | ||
103 | + res=requests.get('https://api.solved.ac/v2/tags/stats.json?page={}'.format(pageNum)) | ||
104 | + tagsResult=json.loads(res.text) | ||
105 | + tags.extend(tagsResult['result']['tags']) | ||
106 | + print('total tags:',len(tags)) | ||
107 | + for tag in tags: | ||
108 | + problemList=[] | ||
109 | + pageNum=1 | ||
110 | + res=requests.get('https://api.solved.ac/v2/search/problems.json?query=solvable:true+tag:{}&page={}&sort=id&sort_direction=ascending'.format(tag['tag_name'],pageNum)) | ||
111 | + problemResult=json.loads(res.text) | ||
112 | + totalPages=problemResult['result']['total_page'] | ||
113 | + problemList.extend(problemResult['result']['problems']) | ||
114 | + for pageNum in range(2,totalPages+1): | ||
115 | + res=requests.get('https://api.solved.ac/v2/search/problems.json?query=solvable:true+tag:{}&page={}&sort=id&sort_direction=ascending'.format(tag['tag_name'],pageNum)) | ||
116 | + problemResult=json.loads(res.text) | ||
117 | + problemList.extend(problemResult['result']['problems']) | ||
118 | + idx=0 | ||
119 | + problemListLen=len(problemList) | ||
120 | + for problemNum in problems['problemNum'].values: | ||
121 | + if idx<problemListLen and int(problemList[idx]['id'])==int(problemNum): | ||
122 | + category=json.loads(problems.loc[problems.problemNum==problemNum,'category'].values[0]) | ||
123 | + category.append(tag['full_name_ko']) | ||
124 | + problems.loc[problems.problemNum==problemNum,'category']=json.dumps(category,ensure_ascii=False) | ||
125 | + idx+=1 | ||
126 | + print('Problem {} in category {}'.format(problemNum,tag['full_name_ko'])) | ||
127 | + save(problems,SAVE_PATH) | ||
128 | + return problems | ||
129 | + | ||
130 | + | ||
131 | +def update_database(problems,client): | ||
132 | + database=client['jaksimsamil'] | ||
133 | + collection=database['problem'] | ||
134 | + dictedProblems=problems.to_dict('records') | ||
135 | + print('len of records:',len(dictedProblems)) | ||
136 | + for dictedProblem in dictedProblems: | ||
137 | + dictedProblem['category']=json.loads(dictedProblem['category']) | ||
138 | + collection.update_one({'problemNum':dictedProblem['problemNum']},{'$set':dictedProblem},upsert=True) | ||
139 | + | ||
140 | + | ||
141 | +if __name__=="__main__": | ||
142 | + startTime=datetime.now() | ||
143 | + client=setup() | ||
144 | + problems=get_khu_problem_list() | ||
145 | + problems=get_problem_info(problems) | ||
146 | + problems=get_solvedac_level(problems) | ||
147 | + problems=get_category(problems) | ||
148 | + update_database(problems,client) | ||
149 | + print('Time elapsed :',(datetime.now()-startTime)/60,'mins') | ||
150 | + |
jaksimsamil-crawler/requirements.txt
0 → 100644
... | @@ -26,17 +26,18 @@ POST http://facerain.dcom.club/profile/getprofile | ... | @@ -26,17 +26,18 @@ POST http://facerain.dcom.club/profile/getprofile |
26 | 26 | ||
27 | ## API Table | 27 | ## API Table |
28 | 28 | ||
29 | -| group | description | method | URL | Detail | Auth | | 29 | +| group | description | method | URL | Detail | Auth | |
30 | -| ------- | -------------------------------------- | ------ | ----------------------- | -------------------------------------- | --------- | | 30 | +| --------- | -------------------------------------- | ------ | -------------------------- | -------------------------------------- | --------- | |
31 | -| profile | 유저가 푼 문제 조회(백준) | GET | api/profile/solvedBJ:id | [바로가기](/src/api/profile/README.md) | None | | 31 | +| profile | 유저가 푼 문제 조회(백준) | GET | api/profile/solvedBJ:id | [바로가기](/src/api/profile/README.md) | None | |
32 | -| profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | [바로가기](/src/api/profile/README.md) | None | | 32 | +| profile | 유저가 푼 문제 동기화(백준) | PATCH | api/profile/syncBJ | [바로가기](/src/api/profile/README.md) | None | |
33 | -| profile | 유저 정보 수정 | POST | api/profile/setprofile | [바로가기](/src/api/profile/README.md) | JWT TOKEN | | 33 | +| profile | 유저 정보 수정 | POST | api/profile/setprofile | [바로가기](/src/api/profile/README.md) | JWT TOKEN | |
34 | -| profile | 유저 정보 받아오기 | POST | api/profile/getprofile | [바로가기](/src/api/profile/README.md) | JWT | | 34 | +| profile | 유저 정보 받아오기 | POST | api/profile/getprofile | [바로가기](/src/api/profile/README.md) | JWT | |
35 | -| profile | 추천 문제 조회 | POST | api/profile/recommend | [바로가기](/src/api/profile/README.md) | None | | 35 | +| profile | 추천 문제 조회 | POST | api/profile/recommend | [바로가기](/src/api/profile/README.md) | None | |
36 | -| profile | 친구 추가 | POST | /api/profile/addfriend | [바로가기](/src/api/profile/README.md) | JWT TOKEN | | 36 | +| profile | 친구 추가 | POST | /api/profile/addfriend | [바로가기](/src/api/profile/README.md) | JWT TOKEN | |
37 | -| notify | 슬랙 메시지 전송 요청 (목표 성취 여부) | POST | api/notify/goal | [바로가기](/src/api/notify/README.md) | Jwt Token | | 37 | +| notify | 슬랙 메시지 전송 요청 (목표 성취 여부) | POST | api/notify/goal | [바로가기](/src/api/notify/README.md) | Jwt Token | |
38 | -| notify | 슬랙 메시지 전송 요청 (문제 추천) | POST | api/notify/recommend | [바로가기](/src/api/notify/README.md) | None | | 38 | +| notify | 슬랙 메시지 전송 요청 (문제 추천) | POST | api/notify/recommend | [바로가기](/src/api/notify/README.md) | None | |
39 | -| auth | 로그인 | POST | api/auth/login | [바로가기](/src/api/auth/README.md) | None | | 39 | +| auth | 로그인 | POST | api/auth/login | [바로가기](/src/api/auth/README.md) | None | |
40 | -| auth | 로그아웃 | POST | api/auth/logout | [바로가기](/src/api/auth/README.md) | JWT Token | | 40 | +| auth | 로그아웃 | POST | api/auth/logout | [바로가기](/src/api/auth/README.md) | JWT Token | |
41 | -| auth | 회원가입 | POST | api/auth/register | [바로가기](/src/api/auth/README.md) | None | | 41 | +| auth | 회원가입 | POST | api/auth/register | [바로가기](/src/api/auth/README.md) | None | |
42 | -| auth | 로그인 확인 | GET | api/auth/check | [바로가기](/src/api/auth/README.md) | None | | 42 | +| auth | 로그인 확인 | GET | api/auth/check | [바로가기](/src/api/auth/README.md) | None | |
43 | +| challenge | 특정 챌린지 조회(이름) | POST | api/challenge/getChallenge | [바로가기]() | None | | ... | ... |
... | @@ -402,12 +402,12 @@ | ... | @@ -402,12 +402,12 @@ |
402 | } | 402 | } |
403 | }, | 403 | }, |
404 | "bcrypt": { | 404 | "bcrypt": { |
405 | - "version": "3.0.8", | 405 | + "version": "5.0.0", |
406 | - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.8.tgz", | 406 | + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.0.tgz", |
407 | - "integrity": "sha512-jKV6RvLhI36TQnPDvUFqBEnGX9c8dRRygKxCZu7E+MgLfKZbmmXL8a7/SFFOyHoPNX9nV81cKRC5tbQfvEQtpw==", | 407 | + "integrity": "sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==", |
408 | "requires": { | 408 | "requires": { |
409 | - "nan": "2.14.0", | 409 | + "node-addon-api": "^3.0.0", |
410 | - "node-pre-gyp": "0.14.0" | 410 | + "node-pre-gyp": "0.15.0" |
411 | } | 411 | } |
412 | }, | 412 | }, |
413 | "bcrypt-pbkdf": { | 413 | "bcrypt-pbkdf": { |
... | @@ -2415,11 +2415,6 @@ | ... | @@ -2415,11 +2415,6 @@ |
2415 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | 2415 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |
2416 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | 2416 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" |
2417 | }, | 2417 | }, |
2418 | - "nan": { | ||
2419 | - "version": "2.14.0", | ||
2420 | - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", | ||
2421 | - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" | ||
2422 | - }, | ||
2423 | "natural-compare": { | 2418 | "natural-compare": { |
2424 | "version": "1.4.0", | 2419 | "version": "1.4.0", |
2425 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", | 2420 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", |
... | @@ -2451,14 +2446,19 @@ | ... | @@ -2451,14 +2446,19 @@ |
2451 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", | 2446 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", |
2452 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" | 2447 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" |
2453 | }, | 2448 | }, |
2449 | + "node-addon-api": { | ||
2450 | + "version": "3.0.0", | ||
2451 | + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz", | ||
2452 | + "integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==" | ||
2453 | + }, | ||
2454 | "node-pre-gyp": { | 2454 | "node-pre-gyp": { |
2455 | - "version": "0.14.0", | 2455 | + "version": "0.15.0", |
2456 | - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", | 2456 | + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", |
2457 | - "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", | 2457 | + "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", |
2458 | "requires": { | 2458 | "requires": { |
2459 | "detect-libc": "^1.0.2", | 2459 | "detect-libc": "^1.0.2", |
2460 | - "mkdirp": "^0.5.1", | 2460 | + "mkdirp": "^0.5.3", |
2461 | - "needle": "^2.2.1", | 2461 | + "needle": "^2.5.0", |
2462 | "nopt": "^4.0.1", | 2462 | "nopt": "^4.0.1", |
2463 | "npm-packlist": "^1.1.6", | 2463 | "npm-packlist": "^1.1.6", |
2464 | "npmlog": "^4.0.2", | 2464 | "npmlog": "^4.0.2", | ... | ... |
... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
5 | "license": "MIT", | 5 | "license": "MIT", |
6 | "dependencies": { | 6 | "dependencies": { |
7 | "axios": "^0.19.2", | 7 | "axios": "^0.19.2", |
8 | - "bcrypt": "^3.0.0", | 8 | + "bcrypt": "^5.0.0", |
9 | "body-parser": "^1.19.0", | 9 | "body-parser": "^1.19.0", |
10 | "cheerio": "^1.0.0-rc.3", | 10 | "cheerio": "^1.0.0-rc.3", |
11 | "cookie-parser": "^1.4.5", | 11 | "cookie-parser": "^1.4.5", | ... | ... |
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"); | ||
4 | /* | 3 | /* |
5 | POST /api/auth/register | 4 | POST /api/auth/register |
6 | { | 5 | { |
... | @@ -28,14 +27,10 @@ exports.register = async (ctx) => { | ... | @@ -28,14 +27,10 @@ exports.register = async (ctx) => { |
28 | ctx.status = 409; | 27 | ctx.status = 409; |
29 | return; | 28 | return; |
30 | } | 29 | } |
31 | - const profile = new Profile({ | ||
32 | - username, | ||
33 | - }); | ||
34 | const user = new User({ | 30 | const user = new User({ |
35 | username, | 31 | username, |
36 | }); | 32 | }); |
37 | await user.setPassword(password); | 33 | await user.setPassword(password); |
38 | - await profile.save(); | ||
39 | await user.save(); | 34 | await user.save(); |
40 | ctx.body = user.serialize(); | 35 | ctx.body = user.serialize(); |
41 | 36 | ... | ... |
1 | +const Challenge = require("../../models/challenge"); | ||
2 | +const Session = require("../../models/session"); | ||
3 | +const Participation = require("../../models/participation"); | ||
4 | +const Group = require("../../models/group"); | ||
5 | +const User = require('../../models/user'); | ||
6 | + | ||
7 | +const Joi = require("joi"); | ||
8 | +/*POST /api/challenge/getChallenge | ||
9 | +{ | ||
10 | + challengeName: "challengeName" | ||
11 | +} | ||
12 | +*/ | ||
13 | +exports.getChallenge = async (ctx) => { | ||
14 | + try { | ||
15 | + const { challengeName } = ctx.request.body; | ||
16 | + const challenge = await Challenge.findByChallengeName(challengeName).select('-_id'); | ||
17 | + if (!challenge) { | ||
18 | + ctx.status = 401; | ||
19 | + return; | ||
20 | + } | ||
21 | + ctx.body = challenge; | ||
22 | + } catch (e) { | ||
23 | + ctx.throw(500, e); | ||
24 | + } | ||
25 | +}; | ||
26 | +/*POST /api/challenge/addChallenge | ||
27 | +{ | ||
28 | + challengeName: "challengeName", | ||
29 | + startDate: Date Object, | ||
30 | + endDate: Date Object, | ||
31 | + durationPerSession: "2w", // '1d' means one day per session, '2w' means 2 weeks per session, '3m' means 3 months per session. | ||
32 | + goalPerSession: 3, | ||
33 | +} | ||
34 | +*/ | ||
35 | +exports.addChallenge = async (ctx) => { | ||
36 | + const schema = Joi.object() | ||
37 | + .keys({ | ||
38 | + challengeName: Joi.string(), | ||
39 | + startDate: Joi.date(), | ||
40 | + endDate: Joi.date(), | ||
41 | + durationPerSession: Joi.string(), | ||
42 | + goalPerSession: Joi.number() | ||
43 | + }) | ||
44 | + .unknown(); | ||
45 | + const result = Joi.validate(ctx.request.body, schema); | ||
46 | + | ||
47 | + if (result.error) { | ||
48 | + ctx.status = 400; | ||
49 | + ctx.body = result.error; | ||
50 | + return; | ||
51 | + } | ||
52 | + let { | ||
53 | + challengeName, | ||
54 | + startDate, | ||
55 | + endDate, | ||
56 | + durationPerSession, | ||
57 | + goalPerSession, | ||
58 | + } = ctx.request.body; | ||
59 | + | ||
60 | + try { | ||
61 | + const isChallengeExist = await Challenge.findByChallengeName(challengeName).select('-_id'); | ||
62 | + | ||
63 | + if (isChallengeExist) { | ||
64 | + ctx.status = 409; | ||
65 | + return; | ||
66 | + } | ||
67 | + const challenge = new Challenge({ | ||
68 | + challengeName, | ||
69 | + startDate, | ||
70 | + endDate, | ||
71 | + durationPerSession, | ||
72 | + goalPerSession, | ||
73 | + }); | ||
74 | + | ||
75 | + await challenge.save(); | ||
76 | + | ||
77 | + const newChallenge=await Challenge.findByChallengeName(challengeName); | ||
78 | + const newChallenge_id=newChallenge._id; | ||
79 | + const timeStep=Number(durationPerSession.slice(0,-1)) | ||
80 | + if(typeof(startDate)=='string'){ | ||
81 | + startDate=new Date(startDate); | ||
82 | + } | ||
83 | + if(typeof(endDate)=='string'){ | ||
84 | + endDate=new Date(endDate); | ||
85 | + } | ||
86 | + for(let s_date=new Date(startDate);s_date<endDate;){ | ||
87 | + let e_date=new Date(s_date); | ||
88 | + if(durationPerSession[durationPerSession.length-1]==='d'){ | ||
89 | + console.log('day'); | ||
90 | + e_date.setDate(s_date.getDate()+timeStep); | ||
91 | + } | ||
92 | + else if(durationPerSession[durationPerSession.length-1]==='w'){ | ||
93 | + console.log('week'); | ||
94 | + e_date.setDate(s_date.getDate()+timeStep*7); | ||
95 | + } | ||
96 | + else if(durationPerSession[durationPerSession.length-1]==='m'){ | ||
97 | + console.log('month'); | ||
98 | + e_date.setMonth(s_date.getMonth()+timeStep); | ||
99 | + } | ||
100 | + e_date.setMinutes(e_date.getMinutes()-1); | ||
101 | + if(e_date>endDate){ | ||
102 | + break; | ||
103 | + } | ||
104 | + let status=""; | ||
105 | + if (s_date>new Date()){ | ||
106 | + status="enrolled"; | ||
107 | + } | ||
108 | + else if (s_date<=new Date() && new Date() <= e_date){ | ||
109 | + status="progress"; | ||
110 | + } | ||
111 | + else{ | ||
112 | + status="end"; | ||
113 | + } | ||
114 | + console.log(`start:${s_date}\nend:${e_date}`); | ||
115 | + const session=new Session({ | ||
116 | + challengeId:newChallenge_id, | ||
117 | + sessionStartDate:s_date, | ||
118 | + sessionEndDate:e_date, | ||
119 | + status:status, | ||
120 | + }); | ||
121 | + await session.save(); | ||
122 | + s_date=new Date(e_date); | ||
123 | + s_date.setMinutes(s_date.getMinutes()+1); | ||
124 | + } | ||
125 | + ctx.body = challenge; | ||
126 | + } catch (e) { | ||
127 | + ctx.throw(500, e); | ||
128 | + } | ||
129 | +}; | ||
130 | + | ||
131 | + | ||
132 | +/* GET /api/challenge/list?status | ||
133 | +query string status can be in ['all','enrolled','progress','end'] | ||
134 | +*/ | ||
135 | +exports.list = async (ctx) => { | ||
136 | + try{ | ||
137 | + const status = ctx.query.status; | ||
138 | + if (status!=='all'){ | ||
139 | + const challenges = await Challenge.find({status:status}).select('-_id'); | ||
140 | + ctx.body = challenges; | ||
141 | + } | ||
142 | + else { | ||
143 | + const challenges = await Challenge.find({}).select('-_id'); | ||
144 | + ctx.body = challenges; | ||
145 | + } | ||
146 | + } | ||
147 | + catch(e){ | ||
148 | + ctx.throw(500,e); | ||
149 | + } | ||
150 | +}; | ||
151 | + | ||
152 | +/* POST /api/challenge/participate | ||
153 | +{ | ||
154 | + username: 'username', | ||
155 | + challengeName: 'challengename' | ||
156 | +} | ||
157 | +*/ | ||
158 | + | ||
159 | +exports.participate=async (ctx)=>{ | ||
160 | + try{ | ||
161 | + /* | ||
162 | + TODO: access token validation, | ||
163 | + recommend:get username from access_token | ||
164 | + */ | ||
165 | + console.log(ctx.request.body); | ||
166 | + const {username,challengeName}=ctx.request.body; | ||
167 | + const challenge=await Challenge.findByChallengeName(challengeName); | ||
168 | + const challenge_id=challenge._id; | ||
169 | + const user=await User.findByUsername(username); | ||
170 | + const user_id=user._id; | ||
171 | + const newGroup=new Group({ | ||
172 | + members:[user_id], | ||
173 | + }); | ||
174 | + let newGroup_id="" | ||
175 | + await newGroup.save(async (err,product)=>{ | ||
176 | + if(err){ | ||
177 | + throw err; | ||
178 | + } | ||
179 | + newGroup_id=product._id; | ||
180 | + const sessions=await Session.findByChallengeId(challenge_id); | ||
181 | + sessions.forEach(async (elem) => { | ||
182 | + const newParticipation=new Participation({ | ||
183 | + sessionId:elem._id, | ||
184 | + groupId:newGroup_id, | ||
185 | + problems:[], | ||
186 | + }); | ||
187 | + await newParticipation.save(); | ||
188 | + }); | ||
189 | + }); | ||
190 | + } | ||
191 | + catch(e){ | ||
192 | + console.error(e); | ||
193 | + ctx.throw(500,e); | ||
194 | + } | ||
195 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +const Router = require('koa-router'); | ||
2 | +const challenge = new Router(); | ||
3 | +const challengeCtrl = require('./challege.ctrl'); | ||
4 | + | ||
5 | +challenge.post("/getchallenge",challengeCtrl.getChallenge); | ||
6 | +challenge.post("/addchallenge",challengeCtrl.addChallenge); | ||
7 | +challenge.get("/list",challengeCtrl.list); | ||
8 | +challenge.post("/participate",challengeCtrl.participate); | ||
9 | + | ||
10 | +module.exports = challenge; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -6,11 +6,13 @@ const friend = require("./friend"); | ... | @@ -6,11 +6,13 @@ const friend = require("./friend"); |
6 | const notify = require("./notify"); | 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 | +const challenge = require("./challenge"); | ||
9 | 10 | ||
10 | api.use("/auth", auth.routes()); | 11 | api.use("/auth", auth.routes()); |
11 | api.use("/friend", friend.routes()); | 12 | api.use("/friend", friend.routes()); |
12 | api.use("/notify", notify.routes()); | 13 | api.use("/notify", notify.routes()); |
13 | api.use("/user", user.routes()); | 14 | api.use("/user", user.routes()); |
14 | api.use("/profile", profile.routes()); | 15 | api.use("/profile", profile.routes()); |
16 | +api.use("/challenge",challenge.routes()); | ||
15 | 17 | ||
16 | module.exports = api; | 18 | module.exports = api; | ... | ... |
1 | -const Profile = require("../../models/profile"); | 1 | +const User = require("../../models/user"); |
2 | const sendSlack = require("../../util/sendSlack"); | 2 | const sendSlack = require("../../util/sendSlack"); |
3 | const problem_set = require("../../data/problem_set"); | 3 | const problem_set = require("../../data/problem_set"); |
4 | const compareBJ = require("../../util/compareBJ"); | 4 | const compareBJ = require("../../util/compareBJ"); |
... | @@ -12,7 +12,7 @@ exports.slackGoal = async (ctx) => { | ... | @@ -12,7 +12,7 @@ exports.slackGoal = async (ctx) => { |
12 | try { | 12 | try { |
13 | const { username } = ctx.request.body; | 13 | const { username } = ctx.request.body; |
14 | 14 | ||
15 | - const profile = await Profile.findByUsername(username); | 15 | + const profile = await User.findByUsername(username); |
16 | if (!profile) { | 16 | if (!profile) { |
17 | ctx.status = 401; | 17 | ctx.status = 401; |
18 | return; | 18 | return; |
... | @@ -62,7 +62,7 @@ exports.slackRecommend = async (ctx) => { | ... | @@ -62,7 +62,7 @@ exports.slackRecommend = async (ctx) => { |
62 | console.log("1"); | 62 | console.log("1"); |
63 | const { username } = ctx.request.body; | 63 | const { username } = ctx.request.body; |
64 | 64 | ||
65 | - const profile = await Profile.findByUsername(username); | 65 | + const profile = await User.findByUsername(username); |
66 | if (!profile) { | 66 | if (!profile) { |
67 | ctx.status = 401; | 67 | ctx.status = 401; |
68 | return; | 68 | return; | ... | ... |
1 | -const Profile = require("../../models/profile"); | 1 | +const User = require("../../models/user"); |
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"); |
... | @@ -16,6 +16,7 @@ exports.checkObjectId = (ctx, next) => { | ... | @@ -16,6 +16,7 @@ exports.checkObjectId = (ctx, next) => { |
16 | } | 16 | } |
17 | return next(); | 17 | return next(); |
18 | }; | 18 | }; |
19 | + | ||
19 | /*POST /api/profile/getprofile | 20 | /*POST /api/profile/getprofile |
20 | { | 21 | { |
21 | username: "username" | 22 | username: "username" |
... | @@ -24,7 +25,7 @@ exports.checkObjectId = (ctx, next) => { | ... | @@ -24,7 +25,7 @@ exports.checkObjectId = (ctx, next) => { |
24 | exports.getProfile = async (ctx) => { | 25 | exports.getProfile = async (ctx) => { |
25 | try { | 26 | try { |
26 | const { username } = ctx.request.body; | 27 | const { username } = ctx.request.body; |
27 | - const profile = await Profile.findByUsername(username); | 28 | + const profile = await User.findByUsername(username); |
28 | if (!profile) { | 29 | if (!profile) { |
29 | ctx.status = 401; | 30 | ctx.status = 401; |
30 | return; | 31 | return; |
... | @@ -50,7 +51,6 @@ exports.setProfile = async (ctx) => { | ... | @@ -50,7 +51,6 @@ exports.setProfile = async (ctx) => { |
50 | //freindList: Joi.array().items(Joi.string()), | 51 | //freindList: Joi.array().items(Joi.string()), |
51 | }) | 52 | }) |
52 | .unknown(); | 53 | .unknown(); |
53 | - console.log(ctx.request.body); | ||
54 | const result = Joi.validate(ctx.request.body, schema); | 54 | const result = Joi.validate(ctx.request.body, schema); |
55 | if (result.error) { | 55 | if (result.error) { |
56 | ctx.status = 400; | 56 | ctx.status = 400; |
... | @@ -59,7 +59,7 @@ exports.setProfile = async (ctx) => { | ... | @@ -59,7 +59,7 @@ exports.setProfile = async (ctx) => { |
59 | } | 59 | } |
60 | 60 | ||
61 | try { | 61 | try { |
62 | - const profile = await Profile.findOneAndUpdate( | 62 | + const profile = await User.findOneAndUpdate( |
63 | { username: ctx.request.body.username }, | 63 | { username: ctx.request.body.username }, |
64 | ctx.request.body, | 64 | ctx.request.body, |
65 | { | 65 | { |
... | @@ -91,7 +91,7 @@ exports.syncBJ = async function (ctx) { | ... | @@ -91,7 +91,7 @@ exports.syncBJ = async function (ctx) { |
91 | } | 91 | } |
92 | 92 | ||
93 | try { | 93 | try { |
94 | - const profile = await Profile.findByUsername(username); | 94 | + const profile = await User.findByUsername(username); |
95 | if (!profile) { | 95 | if (!profile) { |
96 | ctx.status = 401; | 96 | ctx.status = 401; |
97 | return; | 97 | return; |
... | @@ -99,7 +99,7 @@ exports.syncBJ = async function (ctx) { | ... | @@ -99,7 +99,7 @@ exports.syncBJ = async function (ctx) { |
99 | const BJID = await profile.getBJID(); | 99 | const BJID = await profile.getBJID(); |
100 | let BJdata = await getBJ.getBJ(BJID); | 100 | let BJdata = await getBJ.getBJ(BJID); |
101 | let BJdata_date = await analyzeBJ.analyzeBJ(BJdata); | 101 | let BJdata_date = await analyzeBJ.analyzeBJ(BJdata); |
102 | - const updateprofile = await Profile.findOneAndUpdate( | 102 | + const updateprofile = await User.findOneAndUpdate( |
103 | { username: username }, | 103 | { username: username }, |
104 | { solvedBJ: BJdata, solvedBJ_date: BJdata_date }, | 104 | { solvedBJ: BJdata, solvedBJ_date: BJdata_date }, |
105 | { new: true } | 105 | { new: true } |
... | @@ -124,7 +124,7 @@ exports.recommend = async (ctx) => { | ... | @@ -124,7 +124,7 @@ exports.recommend = async (ctx) => { |
124 | return; | 124 | return; |
125 | } | 125 | } |
126 | try { | 126 | try { |
127 | - const profile = await Profile.findByUsername(username); | 127 | + const profile = await User.findByUsername(username); |
128 | if (!profile) { | 128 | if (!profile) { |
129 | ctx.status = 401; | 129 | ctx.status = 401; |
130 | return; | 130 | return; |
... | @@ -134,7 +134,7 @@ exports.recommend = async (ctx) => { | ... | @@ -134,7 +134,7 @@ exports.recommend = async (ctx) => { |
134 | problem_set.problem_set | 134 | problem_set.problem_set |
135 | ); | 135 | ); |
136 | ctx.body = compareBJ.randomItem(unsolved_data); | 136 | ctx.body = compareBJ.randomItem(unsolved_data); |
137 | - //데이터가 비었을 떄 예외처리 필요 | 137 | + //TODO: 데이터가 비었을 떄 예외처리 필요 |
138 | } catch (e) { | 138 | } catch (e) { |
139 | ctx.throw(500, e); | 139 | ctx.throw(500, e); |
140 | } | 140 | } | ... | ... |
... | @@ -2,61 +2,48 @@ const mongoose = require("mongoose"); | ... | @@ -2,61 +2,48 @@ const mongoose = require("mongoose"); |
2 | 2 | ||
3 | const { Schema } = mongoose; | 3 | const { Schema } = mongoose; |
4 | 4 | ||
5 | -const GroupSchema = new Schema({ | 5 | +const ChallengeSchema=new Schema({ |
6 | - members: { type: [String] }, | 6 | + challengeName: {type: String, required: true}, |
7 | + startDate: {type: Object, required: true}, | ||
8 | + endDate: {type: Object, required: true}, | ||
9 | + durationPerSession: {type: String, required: true}, // '1d' means one day per session, '2w' means 2 weeks per session, '3m' means 3 months per session. | ||
10 | + goalPerSession: {type: Number, required:true}, // number of problems for one session | ||
11 | + status: { type: String } | ||
12 | +},{ | ||
13 | + collection: 'challenge' | ||
7 | }); | 14 | }); |
8 | 15 | ||
9 | -const ChallengeSchema = new Schema({ | 16 | +ChallengeSchema.statics.findByChallengeName=function(challengeName){ |
10 | - challengeName: { type: String, required: true }, | 17 | + return this.findOne({challengeName:challengeName}); |
11 | - startDate: { type: Object, required: true }, | 18 | +} |
12 | - endDate: { type: Object, required: true }, | ||
13 | - durationPerSession: { type: String, required: true }, // '1d' means one day per session, '2w' means 2 weeks per session, '3m' means 3 months per session. | ||
14 | - goalPerSession: { type: Number, required: true }, // number of problems for one session | ||
15 | - groups: { type: [GroupSchema], required: true }, // groups attending challenge, group of only one member supposed to be single | ||
16 | -}); | ||
17 | - | ||
18 | -ChallengeSchema.statics.findByChallengeName = function (challengeName) { | ||
19 | - return this.findOne({ challengeName: challengeName }); | ||
20 | -}; | ||
21 | - | ||
22 | -ChallengeSchema.methods.addNewGroup = function (group) { | ||
23 | - this.groups.push(group); | ||
24 | - return this.save(); | ||
25 | -}; | ||
26 | - | ||
27 | -ChallengeSchema.methods.removeGroup = function (group_id) { | ||
28 | - const idx = this.groups.findIndex((item) => item._id === group_id); | ||
29 | - this.groups.splice(idx, 1); | ||
30 | - return this.save(); | ||
31 | -}; | ||
32 | 19 | ||
33 | -ChallengeSchema.methods.getChallengeName = function () { | 20 | +ChallengeSchema.methods.getChallengeName=function(){ |
34 | - return this.challengeName; | 21 | + return this.challengeName; |
35 | -}; | 22 | +} |
36 | 23 | ||
37 | -ChallengeSchema.methods.getStartDate = function () { | 24 | +ChallengeSchema.methods.getStartDate=function(){ |
38 | - return this.startDate; | 25 | + return this.startDate; |
39 | -}; | 26 | +} |
40 | 27 | ||
41 | -ChallengeSchema.methods.getEndDate = function () { | 28 | +ChallengeSchema.methods.getEndDate=function(){ |
42 | - return this.endDate; | 29 | + return this.endDate; |
43 | -}; | 30 | +} |
44 | 31 | ||
45 | -ChallengeSchema.methods.getDurationPerSession = function () { | 32 | +ChallengeSchema.method.getDurationPerSession=function(){ |
46 | - return this.durationPerSession; | 33 | + return this.durationPerSession; |
47 | -}; | 34 | +} |
48 | 35 | ||
49 | -ChallengeSchema.methods.getGoalPerSession = function () { | 36 | +ChallengeSchema.methods.getGoalPerSession=function(){ |
50 | - return this.goalPerSession; | 37 | + return this.goalPerSession; |
51 | -}; | 38 | +} |
52 | 39 | ||
53 | -ChallengeSchema.methods.getGroups = function () { | 40 | +ChallengeSchema.methods.getStatus=function(){ |
54 | - return this.groups; | 41 | + return this.status; |
55 | -}; | 42 | +} |
56 | 43 | ||
57 | -ChallengeSchema.methods.serialize = function () { | 44 | +ChallengeSchema.methods.serialize=function(){ |
58 | - return this.toJSON(); | 45 | + return this.toJSON(); |
59 | -}; | 46 | +} |
60 | 47 | ||
61 | -const Challenge = mongoose.model("Challenge", ChallengeSchema); | 48 | +const Challenge = mongoose.model('Challenge', ChallengeSchema); |
62 | -module.exports = Challenge; | 49 | +module.exports = Challenge; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
jaksimsamil-server/src/models/group.js
0 → 100644
1 | +const mongoose = require("mongoose"); | ||
2 | + | ||
3 | +const { Schema } = mongoose; | ||
4 | + | ||
5 | +const GroupSchema = new Schema({ | ||
6 | + members: [{ type: Schema.Types.ObjectId, ref: 'User' }] | ||
7 | +},{ | ||
8 | + collection: 'group' | ||
9 | +}); | ||
10 | + | ||
11 | +GroupSchema.methods.addGroupMemeber=function(user){ | ||
12 | + this.members.push(user._id); | ||
13 | + return this.save(); | ||
14 | +} | ||
15 | + | ||
16 | +GroupSchema.methods.getMembers=function(){ | ||
17 | + return this.members; | ||
18 | +} | ||
19 | + | ||
20 | +GroupSchema.methods.serialize=function(){ | ||
21 | + return this.toJSON(); | ||
22 | +} | ||
23 | + | ||
24 | +const Group = mongoose.model('Group',GroupSchema); | ||
25 | +module.exports = Group; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +const mongoose = require("mongoose"); | ||
2 | + | ||
3 | +const { Schema } = mongoose; | ||
4 | + | ||
5 | +const SelectedProblemSchema=new Schema({ | ||
6 | + problemNum: {type: Number, required: true}, | ||
7 | + isSolved: {type:Boolean, default: false}, | ||
8 | +},{ | ||
9 | + _id: false | ||
10 | +}); | ||
11 | + | ||
12 | +const ParticipationSchema = new Schema({ | ||
13 | + sessionId: { type: Schema.Types.ObjectId, ref: 'Session' }, | ||
14 | + groupId: { type: Schema.Types.ObjectId, ref: 'Group' }, | ||
15 | + problems: [{type:SelectedProblemSchema}] | ||
16 | +},{ | ||
17 | + collection: 'particiaption' | ||
18 | +}); | ||
19 | + | ||
20 | +ParticipationSchema.statics.findBySessionId=function(session){ | ||
21 | + return this.find({sessionId:session._id}); | ||
22 | +} | ||
23 | + | ||
24 | +ParticipationSchema.statics.findByGroupId=function(group){ | ||
25 | + return this.find({groupId:group._id}); | ||
26 | +} | ||
27 | + | ||
28 | +ParticipationSchema.methods.addProblem=function(problem){ | ||
29 | + this.problems.push({problemNum:problem.problemNum,isSolved:problem.isSolved}); | ||
30 | +} | ||
31 | + | ||
32 | +const Participation = mongoose.model('Participation', ParticipationSchema); | ||
33 | +module.exports = Participation; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -8,7 +8,10 @@ const ProblemSchema=new Schema({ | ... | @@ -8,7 +8,10 @@ const ProblemSchema=new Schema({ |
8 | solvedacLevel: {type: Number}, | 8 | solvedacLevel: {type: Number}, |
9 | sumbitNum: {type: Number, required: true}, | 9 | sumbitNum: {type: Number, required: true}, |
10 | correctNum: {type: Number, required: true}, | 10 | correctNum: {type: Number, required: true}, |
11 | - category: {type:[String]} | 11 | + count: { type: Number }, |
12 | + category: [{ type:String }], | ||
13 | +},{ | ||
14 | + collection: 'problem' | ||
12 | }); | 15 | }); |
13 | 16 | ||
14 | ProblemSchema.statics.findByProblemNum=function(problemNum){ | 17 | ProblemSchema.statics.findByProblemNum=function(problemNum){ |
... | @@ -46,6 +49,10 @@ ProblemSchema.methods.getCorrectNum=function(){ | ... | @@ -46,6 +49,10 @@ ProblemSchema.methods.getCorrectNum=function(){ |
46 | return this.correctNum; | 49 | return this.correctNum; |
47 | } | 50 | } |
48 | 51 | ||
52 | +ProblemSchema.methods.getCount=function(){ | ||
53 | + return this.count; | ||
54 | +} | ||
55 | + | ||
49 | ProblemSchema.methods.getCategory=function(){ | 56 | ProblemSchema.methods.getCategory=function(){ |
50 | return this.category; | 57 | return this.category; |
51 | } | 58 | } |
... | @@ -54,5 +61,5 @@ ProblemSchema.methods.serialize=function(){ | ... | @@ -54,5 +61,5 @@ ProblemSchema.methods.serialize=function(){ |
54 | return this.toJSON(); | 61 | return this.toJSON(); |
55 | } | 62 | } |
56 | 63 | ||
57 | -const Problem=mongoose.model('Problem',ProblemSchema); | ||
58 | -module.exports=Problem; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
64 | +const Problem = mongoose.model('Problem',ProblemSchema); | ||
65 | +module.exports = Problem; | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
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 | - solvedBJ_date: Object, | ||
10 | - friendList: [String], | ||
11 | - slackWebHookURL: String, | ||
12 | - goalNum: Number, | ||
13 | -}); | ||
14 | -ProfileSchema.statics.findByUsername = function (username) { | ||
15 | - return this.findOne({ username }); | ||
16 | -}; | ||
17 | -ProfileSchema.methods.getBJID = function () { | ||
18 | - return this.userBJID; | ||
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 | -}; | ||
34 | - | ||
35 | -ProfileSchema.methods.serialize = function () { | ||
36 | - const data = this.toJSON(); | ||
37 | - return data; | ||
38 | -}; | ||
39 | -const Profile = mongoose.model("Profile", ProfileSchema); | ||
40 | -module.exports = Profile; |
jaksimsamil-server/src/models/session.js
0 → 100644
1 | +const mongoose = require("mongoose"); | ||
2 | + | ||
3 | +const { Schema } = mongoose; | ||
4 | + | ||
5 | +const SessionSchema = new Schema({ | ||
6 | + challengeId: { type: Schema.Types.ObjectId, ref: 'Challenge' }, | ||
7 | + sessionStartDate: { type: Object }, | ||
8 | + sessionEndDate: { type: Object }, | ||
9 | + status: { type: String } | ||
10 | +},{ | ||
11 | + collection: 'session' | ||
12 | +}); | ||
13 | + | ||
14 | +SessionSchema.statics.findByChallengeId=function(challenge){ | ||
15 | + return this.find({challengeId:challenge._id}); | ||
16 | +} | ||
17 | + | ||
18 | +SessionSchema.methods.getSessionStartDate=function(){ | ||
19 | + return this.sessionStartDate; | ||
20 | +} | ||
21 | + | ||
22 | +SessionSchema.methods.getSessionEndDate=function(){ | ||
23 | + return this.sessionEndDate; | ||
24 | +} | ||
25 | + | ||
26 | +SessionSchema.methods.getStatus=function(){ | ||
27 | + return this.status; | ||
28 | +} | ||
29 | + | ||
30 | +SessionSchema.methods.serialize=function(){ | ||
31 | + return this.toJSON(); | ||
32 | +} | ||
33 | + | ||
34 | +const Session = mongoose.model('Session', SessionSchema); | ||
35 | +module.exports = Session; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -7,8 +7,25 @@ const Schema = mongoose.Schema; | ... | @@ -7,8 +7,25 @@ const Schema = mongoose.Schema; |
7 | const UserSchema = new Schema({ | 7 | const UserSchema = new Schema({ |
8 | username: String, | 8 | username: String, |
9 | hashedPassword: String, | 9 | hashedPassword: String, |
10 | + userBJID: String, | ||
11 | + sovledBJ: Object, | ||
12 | + solvedBJ_date: Object, | ||
13 | + friendList: [{ type: Schema.Types.ObjectId, ref: 'User' }], | ||
14 | + slackWebHookURL: String, | ||
15 | + goalNum: Number, | ||
16 | +},{ | ||
17 | + collection: 'user' | ||
10 | }); | 18 | }); |
11 | 19 | ||
20 | +UserSchema.statics.findByUsername = function (username) { | ||
21 | + return this.findOne({ username }); | ||
22 | +}; | ||
23 | + | ||
24 | +UserSchema.methods.addFriend=function(friend){ | ||
25 | + this.friendList.push(friend._id); | ||
26 | + return this.save(); | ||
27 | +} | ||
28 | + | ||
12 | UserSchema.methods.setPassword = async function (password) { | 29 | UserSchema.methods.setPassword = async function (password) { |
13 | const hash = await bcrypt.hash(password, 10); | 30 | const hash = await bcrypt.hash(password, 10); |
14 | this.hashedPassword = hash; | 31 | this.hashedPassword = hash; |
... | @@ -17,14 +34,13 @@ UserSchema.methods.checkPassword = async function (password) { | ... | @@ -17,14 +34,13 @@ UserSchema.methods.checkPassword = async function (password) { |
17 | const result = await bcrypt.compare(password, this.hashedPassword); | 34 | const result = await bcrypt.compare(password, this.hashedPassword); |
18 | return result; | 35 | return result; |
19 | }; | 36 | }; |
20 | -UserSchema.statics.findByUsername = function (username) { | 37 | + |
21 | - return this.findOne({ username }); | ||
22 | -}; | ||
23 | UserSchema.methods.serialize = function () { | 38 | UserSchema.methods.serialize = function () { |
24 | const data = this.toJSON(); | 39 | const data = this.toJSON(); |
25 | delete data.hashedPassword; | 40 | delete data.hashedPassword; |
26 | return data; | 41 | return data; |
27 | }; | 42 | }; |
43 | + | ||
28 | UserSchema.methods.generateToken = function () { | 44 | UserSchema.methods.generateToken = function () { |
29 | const token = jwt.sign( | 45 | const token = jwt.sign( |
30 | { | 46 | { |
... | @@ -38,5 +54,32 @@ UserSchema.methods.generateToken = function () { | ... | @@ -38,5 +54,32 @@ UserSchema.methods.generateToken = function () { |
38 | ); | 54 | ); |
39 | return token; | 55 | return token; |
40 | }; | 56 | }; |
57 | + | ||
58 | +UserSchema.statics.findByUsername = function (username) { | ||
59 | + return this.findOne({ username }); | ||
60 | +}; | ||
61 | + | ||
62 | +UserSchema.methods.getBJID = function () { | ||
63 | + return this.userBJID; | ||
64 | +}; | ||
65 | + | ||
66 | +UserSchema.methods.getBJdata = function () { | ||
67 | + return this.solvedBJ; | ||
68 | +}; | ||
69 | + | ||
70 | +UserSchema.methods.getslackURL = function () { | ||
71 | + return this.slackWebHookURL; | ||
72 | +}; | ||
73 | + | ||
74 | +UserSchema.methods.getgoalNum = function () { | ||
75 | + return this.goalNum; | ||
76 | +}; | ||
77 | + | ||
78 | +UserSchema.methods.getTodaySovled = function () { | ||
79 | + if (this.solvedBJ_date) { | ||
80 | + return this.solvedBJ_date.presentNum; | ||
81 | + } | ||
82 | +}; | ||
83 | + | ||
41 | const User = mongoose.model("User", UserSchema); | 84 | const User = mongoose.model("User", UserSchema); |
42 | module.exports = User; | 85 | module.exports = User; | ... | ... |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment