R/grades2.R

.DSRGrades.class <- structure("DSRGrades", package = .packageName)

#'@title Creator of the DSRGrades Object
#'@param user_ids character vector. The ids in the DSR system. For example: \code{c("classroom:wush")}.
#'@export
get.grades.obj <- function(user_ids) {
  grades <- rep(0, length(user_ids))
  names(grades) <- user_ids
  comments <- lapply(length(user_ids) %>% seq_len, function(i) {
    list()
  })
  names(comments) <- user_ids
  .r <- list(grades = grades, comments = comments)
  class(.r) <- .DSRGrades.class
  .r
}

#'@title Update the DSRGrades Object
#'@param grades.obj DSRGrades object, which is generated by \code{get.grades.obj}.
#'@param records data.frame. The records downloaded by \code{get.records}.
#'@param course.grades named numeric vector. The name is the course name in the DSR system.
#'The value is the score of the course. For example: \code{c("NTUR01:HW1" = 10, "NTUR01:HW2" = 10)}.
#'@param due.time POSIXct object. The due time of the course.
#'@param decay.per.day numeric number. The decay of the score per day.
update.grades.obj <- function(grades.obj, records, course.grades, due.time, decay.per.day = 5 / 100) {
  # checking params
  stopifnot(isTRUE(all.equal(class(grades.obj), .DSRGrades.class)))
  stopifnot(is.data.frame(records))
  stopifnot(is.numeric(course.grades))
  stopifnot(!is.null(names(course.grades)))
  stopifnot(isTRUE(all.equal(class(due.time), class(Sys.time()))))
  # initialization
  grades <- grades.obj$grades
  comments <- grades.obj$comments
  user_ids <- names(grades)
  course.target <- names(course.grades)
  targets <- dplyr::filter(records, course %in% course.target)
  result <- list()
  for(user_id.value in user_ids) {
    print(user_id.value)
    result[[user_id.value]] <- list()
    df1 <- dplyr::filter(targets, user_id == user_id.value)
    for(course.value in course.target) {
      df2 <- dplyr::filter(df1, course == course.value)
      print(nrow(df2))
      if (nrow(df2) == 0) {
        result[[user_id.value]][[course.value]] <- list(type = "X", last = NULL)
      } else if (all(df2$type == 0)) {
        result[[user_id.value]][[course.value]] <- list(type = "P", last = max(df2$created_at))
      } else {
        stopifnot(any(df2$type == 1))
        result[[user_id.value]][[course.value]] <- list(type = "O", first = min(df2$created_at[df2$type == 1]))
      }
    }
  }
  for(user_id.value in user_ids) {
    df1 <- result[[user_id.value]]
    user <- user_id.value
    for(course.value in course.target) {
      if (df1[[course.value]]$type == "O") {
        if (df1[[course.value]]$first < due.time) {
          grades[user] <- grades[user] + course.grades[course.value]
#          comments[[user]]$finish.ontime <- c(comments[[user]]$finish.ontime, course.value)
          comments[[user]]$finish.ontime <- rbind(
            make.row.names = FALSE,
            comments[[user]]$finish.ontime,
            data.frame(
              stringsAsFactors = FALSE,
              course = course.value,
              grades = course.grades[course.value]
              )
          )
        } else {
          delay.days <- difftime(df1[[course.value]]$first, due.time, units = "days") %>%
            ceiling() %>%
            as.integer()
          decay.rate <- 1 - delay.days * decay.per.day
          decay.grades <- max(0, course.grades[course.value] * decay.rate)
          grades[user] <- grades[user] + decay.grades
          comments[[user]]$finish.delay <- rbind(
            comments[[user]]$finish.delay,
            data.frame(
              stringsAsFactors = FALSE,
              course = course.value,
              days = delay.days,
              grades = decay.grades
            )
          )
          cat(sprintf("%s's %s is delayed %d days\n", user, course.value, delay.days))
        }
      } else if (df1[[course.value]]$type == "P") {
        comments[[user]]$processing <- c(comments[[user]]$processing, course.value)
      } else if (df1[[course.value]]$type == "X") {
        comments[[user]]$no.action <- c(comments[[user]]$no.action, course.value)
      } else stop("")
    }
  }
  .r <- list(grades = grades, comments = comments)
  class(.r) <- .DSRGrades.class
  .r
}

#'@export
#'@param comments.obj list. Example: \code{grades.obj$comments[[user_id]]}.
get.comment <- function(comments.obj) {
  comments <- ""
  if ("finish.ontime" %in% names(comments.obj)) {
    comments <- append(comments, sprintf("你在時限之內完成的單元: \n%s", sprintf(fmt = "\t%s(獲得的分數為: %s分)\n", comments.obj$finish.ontime$course, comments.obj$finish.ontime$grades) %>% paste(collapse = "")))
  }
  if ("finish.delay" %in% names(comments.obj)) {
    comments <- append(comments, sprintf("你遲交的單元: "))
    comments <- append(
      comments,
      apply(comments.obj$finish.delay, 1, function(obj) {
        sprintf("\t%s (遲交 %s 天,獲得的分數為: %s分)\n", obj["course"], obj["days"], obj["grades"])
      }) %>%
        paste(collapse = "")
    )
  }
  if ("processing" %in% names(comments.obj)) {
    comments <- append(comments, sprintf("你正在進行中的單元: \n%s", comments.obj$processing %>% sprintf(fmt = "\t%s\n") %>% paste(collapse = "")))
  }
  if ("no.action" %in% names(comments.obj)) {
    comments <- append(comments, sprintf("你還沒有動作的單元: \n%s", comments.obj$no.action %>% sprintf(fmt = "\t%s\n") %>% paste(collapse = "")))
  }
  comments <- paste(comments, collapse = "\n")
  comments
}
wush978/DSRTeacher documentation built on May 29, 2019, 2:29 p.m.