JJuOn

Implement problem recommendation algorithm

...@@ -3,5 +3,6 @@ const session = new Router(); ...@@ -3,5 +3,6 @@ const session = new Router();
3 const sessionCtrl = require('./session.ctrl'); 3 const sessionCtrl = require('./session.ctrl');
4 4
5 session.post("/createproblem/:how",sessionCtrl.createProblem); 5 session.post("/createproblem/:how",sessionCtrl.createProblem);
6 +session.get("/status",sessionCtrl.status);
6 7
7 module.exports = session; 8 module.exports = session;
...\ No newline at end of file ...\ No newline at end of file
......
1 +const axios = require("axios");
1 const Participation = require("../../models/participation"); 2 const Participation = require("../../models/participation");
2 const Session = require("../../models/session"); 3 const Session = require("../../models/session");
3 const Group = require("../../models/group"); 4 const Group = require("../../models/group");
4 const User = require("../../models/user"); 5 const User = require("../../models/user");
6 +const Challenge = require("../../models/challenge");
7 +const Problem = require("../../models/problem");
5 const mongoose = require("mongoose"); 8 const mongoose = require("mongoose");
6 9
7 const {ObjectId} = mongoose.Types; 10 const {ObjectId} = mongoose.Types;
8 11
9 /* POST /api/session/createproblem/:how 12 /* POST /api/session/createproblem/:how
10 { 13 {
11 - sessionId: ObjectId, 14 + sessionId: ObjectId or String,
12 - groupId: ObjectId, 15 + groupId: ObjectId or String,
13 - problemList:[Number], 16 + problemList:[Number], (optional)
14 } 17 }
15 */ 18 */
16 exports.createProblem = async (ctx)=>{ 19 exports.createProblem = async (ctx)=>{
...@@ -25,15 +28,20 @@ exports.createProblem = async (ctx)=>{ ...@@ -25,15 +28,20 @@ exports.createProblem = async (ctx)=>{
25 if(typeof(problemList)==='string'){ 28 if(typeof(problemList)==='string'){
26 problemList=JSON.parse(problemList); 29 problemList=JSON.parse(problemList);
27 } 30 }
31 + const session = await Session.findById(sessionId);
32 + const challengeId = session['challengeId'];
33 + const challenge = await Challenge.findById(challengeId);
34 + const goalPerSession = challenge['goalPerSession'];
28 const participation = await Participation.findOne({sessionId:sessionId,groupId:groupId}); 35 const participation = await Participation.findOne({sessionId:sessionId,groupId:groupId});
29 const group = await Group.findById(groupId); 36 const group = await Group.findById(groupId);
30 const how=ctx.params.how; 37 const how=ctx.params.how;
31 if(how==='self'){ 38 if(how==='self'){
39 + if(problemList.length!==goalPerSession){
40 + ctx.throw(400,'문제 수가 맞지 않습니다.');
41 + }
32 let check = true; 42 let check = true;
33 for(let i=0;i<group.members.length;i++){ 43 for(let i=0;i<group.members.length;i++){
34 const user = await User.findById(group.members[i]); 44 const user = await User.findById(group.members[i]);
35 - console.log(user);
36 - console.log(typeof(user.solvedBJ_date.solvedBJbyDATE));
37 let userProblemList = []; 45 let userProblemList = [];
38 for(let key in user.solvedBJ_date.solvedBJbyDATE){ 46 for(let key in user.solvedBJ_date.solvedBJbyDATE){
39 userProblemList.push(user.solvedBJ_date.solvedBJbyDATE[key]); 47 userProblemList.push(user.solvedBJ_date.solvedBJbyDATE[key]);
...@@ -47,7 +55,7 @@ exports.createProblem = async (ctx)=>{ ...@@ -47,7 +55,7 @@ exports.createProblem = async (ctx)=>{
47 } 55 }
48 } 56 }
49 if(!check){ 57 if(!check){
50 - ctx.throw('그룹원이 이미 푼 문제는 등록할 수 없습니다.'); 58 + ctx.throw(400,'그룹원이 이미 푼 문제는 등록할 수 없습니다.');
51 return; 59 return;
52 } 60 }
53 else{ 61 else{
...@@ -56,10 +64,72 @@ exports.createProblem = async (ctx)=>{ ...@@ -56,10 +64,72 @@ exports.createProblem = async (ctx)=>{
56 } 64 }
57 } 65 }
58 else if(how==='recommend'){ 66 else if(how==='recommend'){
59 - //TODO 67 + let groupProblemList=[];
68 + let selectedProblemList=[];
69 + for(let i=0;i<group.members.length;i++){
70 + const user = await User.findById(group.members[i]);
71 + for(let key in user.solvedBJ_date.solvedBJbyDATE){
72 + groupProblemList.push(user.solvedBJ_date.solvedBJbyDATE[key]);
73 + }
74 + }
75 + groupProblemList=groupProblemList.flat().sort((a,b)=>new Date(b.solvedDate)-new Date(a.solvedDate)).map(elem=>elem.problem_number);
76 + groupProblemList=groupProblemList.filter((x,i)=>groupProblemList.indexOf(x)===i);
77 + console.log(groupProblemList);
78 + const problems=await Problem.find({}).sort({count:-1});
79 + console.log(problems);
80 + console.log(goalPerSession);
81 + for(let i=0;i<problems.length;i++){
82 + if(!groupProblemList.includes(String(problems[i].problemNum))){
83 + selectedProblemList.push(String(problems[i].problemNum));
84 + }
85 + if(selectedProblemList.length===goalPerSession || i/problems.length >= 0.75){
86 + break;
87 + }
88 + }
89 + for(let i=0; i<groupProblemList.length && selectedProblemList.length < goalPerSession; i++){
90 + const p = await Problem.findOne({problemNum:groupProblemList[i]});
91 + if( Number(p.solvedacLevel)< 1 || Number(p.solvedacLevel)>30 ){
92 + continue;
93 + }
94 + const body = await axios.get(`https://api.solved.ac/v2/search/problems.json?query=solvable:true+tier:${p.solvedacLevel}&page=1&sort=solved&sort_direction=desc`);
95 + let data = body.data;
96 + if(typeof(data)==='string'){
97 + data=JSON.parse(data);
98 + }
99 + for(let j=0;j<data.result.problems.length;j++){
100 + if(!groupProblemList.includes(data.result.problems[j].id)){
101 + selectedProblemList.push(data.result.problems[j].id.toString());
102 + break;
103 + }
104 + }
105 + }
106 + selectedProblemList.map(async problemNum=>await participation.addProblem({problemNum:problemNum,isSolved:false}));
107 + ctx.body=participation.serialize();
60 } 108 }
61 } 109 }
62 catch(e){ 110 catch(e){
111 + console.error(e);
112 + ctx.throw(500,e);
113 + }
114 +};
115 +
116 +
117 +// GET /api/session/status?sessionId&groupId
118 +
119 +exports.status=async (ctx)=>{
120 + try{
121 + let {sessionId,groupId}=ctx.request.query;
122 + if(typeof(sessionId)==='string'){
123 + sessionId=new ObjectId(sessionId);
124 + }
125 + if(typeof(groupId)==='string'){
126 + groupId=new ObjectId(groupId);
127 + }
128 + const participation=await Participation.findOne({sessionId:sessionId,groupId:groupId});
129 + const group = await Group.findById(groupId);
130 +
131 + }
132 + catch(e){
63 ctx.throw(500,e); 133 ctx.throw(500,e);
64 } 134 }
65 -};
...\ No newline at end of file ...\ No newline at end of file
135 +}
...\ No newline at end of file ...\ No newline at end of file
......