challege.ctrl.js 6.16 KB
const Challenge = require("../../models/challenge");
const Session = require("../../models/session");
const Participation = require("../../models/participation");
const Group = require("../../models/group");
const User = require("../../models/user");

const Joi = require("joi");
/*POST /api/challenge/getChallenge
{
    challengeName: "challengeName"
}
*/
exports.getChallengePOST = async (ctx) => {
  try {
    const { challengeName } = ctx.request.body;
    const challenge = await Challenge.findByChallengeName(challengeName);
    if (!challenge) {
      ctx.status = 401;
      return;
    }
    ctx.body = challenge.serialize();
  } catch (e) {
    ctx.throw(500, e);
  }
};
/*POST /api/challenge/addChallenge
{
    challengeName: "challengeName",
    startDate: Date Object,
    endDate: Date Object,
    durationPerSession: "2w", // '1d' means one day per session, '2w' means 2 weeks per session, '3m' means 3 months per session.
    goalPerSession: 3,
}
*/
exports.addChallenge = async (ctx) => {
  const schema = Joi.object()
    .keys({
      challengeName: Joi.string(),
      startDate: Joi.date(),
      endDate: Joi.date(),
      durationPerSession: Joi.string(),
      goalPerSession: Joi.number(),
    })
    .unknown();
  const result = Joi.validate(ctx.request.body, schema);

  if (result.error) {
    ctx.status = 400;
    ctx.body = result.error;
    return;
  }
  let {
    challengeName,
    startDate,
    endDate,
    durationPerSession,
    goalPerSession,
  } = ctx.request.body;

  try {
    const isChallengeExist = await Challenge.findByChallengeName(challengeName);

    if (isChallengeExist) {
      ctx.status = 409;
      return;
    }
    const challenge = new Challenge({
      challengeName,
      startDate,
      endDate,
      durationPerSession,
      goalPerSession,
    });

    await challenge.save();

    const newChallenge = await Challenge.findByChallengeName(challengeName);
    const newChallenge_id = newChallenge._id;
    const timeStep = Number(durationPerSession.slice(0, -1));
    if (typeof startDate == "string") {
      startDate = new Date(startDate);
    }
    if (typeof endDate == "string") {
      endDate = new Date(endDate);
    }
    for (let s_date = new Date(startDate); s_date < endDate; ) {
      let e_date = new Date(s_date);
      if (durationPerSession[durationPerSession.length - 1] === "d") {
        console.log("day");
        e_date.setDate(s_date.getDate() + timeStep);
      } else if (durationPerSession[durationPerSession.length - 1] === "w") {
        console.log("week");
        e_date.setDate(s_date.getDate() + timeStep * 7);
      } else if (durationPerSession[durationPerSession.length - 1] === "m") {
        console.log("month");
        e_date.setMonth(s_date.getMonth() + timeStep);
      }
      e_date.setMinutes(e_date.getMinutes() - 1);
      if (e_date > endDate) {
        break;
      }
      let status = "";
      if (s_date > new Date()) {
        status = "enrolled";
      } else if (s_date <= new Date() && new Date() <= e_date) {
        status = "progress";
      } else {
        status = "end";
      }
      console.log(`start:${s_date}\nend:${e_date}`);
      const session = new Session({
        challengeId: newChallenge_id,
        sessionStartDate: s_date,
        sessionEndDate: e_date,
        status: status,
      });
      await session.save();
      s_date = new Date(e_date);
      s_date.setMinutes(s_date.getMinutes() + 1);
      await challenge.updateOne({ status: status });
    }

    ctx.body = challenge.serialize();
  } catch (e) {
    ctx.throw(500, e);
  }
};

/* GET /api/challenge/list/:status
parameter status can be in ['all','enrolled','progress','end']
*/
exports.list = async (ctx) => {
  try {
    const status = ctx.params.status;
    if (status !== "all") {
      const challenges = await Challenge.find({ status: status });
      ctx.body = challenges;
    } else {
      const challenges = await Challenge.find({});
      ctx.body = challenges;
    }
  } catch (e) {
    ctx.throw(500, e);
  }
};

/* POST /api/challenge/participate
{
  username: 'username',
  challengeName: 'challengename'
}
*/

exports.participate = async (ctx) => {
  try {
    /*
  TODO: access token validation,
  recommend:get username from access_token
  */
    console.log(ctx.request.body);
    const { username, challengeName } = ctx.request.body;
    const challenge = await Challenge.findByChallengeName(challengeName);
    const challenge_id = challenge._id;
    const user = await User.findByUsername(username);
    const user_id = user._id;
    const newGroup = new Group({
      groupName: `${user.username}${challengeName} 그룹`,
      members: [user_id],
    });
    let newGroup_id = "";
    await newGroup.save(async (err, product) => {
      if (err) {
        throw err;
      }
      newGroup_id = product._id;
      const sessions = await Session.findByChallengeId(challenge_id);
      sessions.forEach(async (elem) => {
        const newParticipation = new Participation({
          sessionId: elem._id,
          groupId: newGroup_id,
          problems: [],
        });
        await newParticipation.save();
        ctx.body = newParticipation.serialize();
      });
    });
  } catch (e) {
    console.error(e);
    ctx.throw(500, e);
  }
};

/*
GET /api/challenge/getchallenge?username
*/
exports.getChallengeGET = async (ctx)=>{
  try{
    const {username} = ctx.request.query;
    const user = await User.findByUsername(username);
    const user_id=user._id;
    const groups = await Group.find();
    const userIncludedGroups = [];
    for(let i=0;i<groups.length;i++){
      if(groups[i].members.includes(user_id)){
        userIncludedGroups.push(groups[i]);
      }
    }
    const challengeList = [];
    for(let i=0;i<userIncludedGroups.length;i++){
      const participations = await Participation.findByGroupId(userIncludedGroups[i]._id);
      for(let j=0;j<participations.length;j++){
        const session = await Session.findById(participations[j].sessionId);
        const challenge = await Challenge.findById(session.challengeId);
        if(!challengeList.includes(challenge)){
          challengeList.push(challenge);
        }
      }
    }
    ctx.body = challengeList.map(c=>c.serialize());
  }
  catch(e){
    ctx.throw(500,e);
  }
}