func (ada *Adapter) AssignmentDetail(courseId, id string) (title, body string, attach *model.Attachment, status int, errMsg error) { status = http.StatusOK url := AssignmentDetailURL(courseId, id) doc, err := ada.GetDocument(url) if err != nil { status = http.StatusBadGateway errMsg = err return } var attachSel *goquery.Selection // Careful, I remembered assignments could contain HTML before. if content := doc.Find("#table_box>tbody>tr>td.title+td"); content.Size() != 5 { errMsg = fmt.Errorf("Expect 5 content blocks, got %d.", content.Size()) } else { attachSel = content.Eq(2) texts := util.TrimmedTexts(content) title = texts[0] body = texts[1] } if errMsg != nil { status = http.StatusInternalServerError errMsg = fmt.Errorf("Failed to parse %s: %s", url, errMsg) return } attach, status, errMsg = ada.Attachment(attachSel) return }
func (ada *Adapter) Submission(courseId, id string) (submission *model.Submission, status int, errMsg error) { status = http.StatusOK url := SubmissionURL(courseId, id) doc, err := ada.GetDocument(url) if err != nil { status = http.StatusBadGateway errMsg = err return } var attachSel, commentAttachSel *goquery.Selection // Careful, I remembered assignments could contain HTML before. if content := doc.Find("#table_box>tbody>tr>td.title+td"); content.Size() != 8 { errMsg = fmt.Errorf("Expect 8 content blocks, got %d.", content.Size()) } else { texts := util.TrimmedTexts(content) markStr := texts[5] if mark, err := ParseMark(markStr); err != nil { errMsg = fmt.Errorf("Failed to parse mark from %s: %s", markStr, err) } else { attachSel = content.Eq(2) commentAttachSel = content.Eq(7) submission = &model.Submission{ AssignmentId: id, Late: false, // Or we cannot view it now. Body: texts[1], } if markedAt := texts[4]; markedAt != "null" { if name := texts[3]; name != "" { submission.MarkedBy = &model.User{Name: name} } submission.MarkedAt = markedAt submission.Mark = mark submission.Comment = texts[6] } } } if errMsg != nil { status = http.StatusInternalServerError errMsg = fmt.Errorf("Failed to parse %s: %s", url, errMsg) return } sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { submission.Attachment, *status, *err = ada.Attachment(attachSel) }) sg.Go(func(status *int, err *error) { submission.CommentAttachment, *status, *err = ada.Attachment(commentAttachSel) }) status, errMsg = sg.Wait() return }
func (ada *Adapter) AssignmentList(courseId string) (assignments []*model.Assignment, status int, errMsg error) { status = http.StatusOK url := AssignmentsURL(courseId) doc, err := ada.GetDocument(url) if err != nil { status = http.StatusBadGateway errMsg = err return } rows := doc.Find("tr.tr1, tr.tr2") assignments = make([]*model.Assignment, rows.Size()) rows.EachWithBreak(func(i int, s *goquery.Selection) bool { if cols := s.Children(); cols.Size() != 6 { errMsg = fmt.Errorf("Expect 6 columns, got %d.", cols.Size()) } else if link := cols.Eq(0).Find("a"); link.Size() == 0 { errMsg = fmt.Errorf("Failed to find link in column 0.") } else if _, id := ParseAssignmentDetailURL(link.AttrOr("href", "")); id == "" { errMsg = fmt.Errorf("Failed to find assignment id from href (%s).", link.AttrOr("href", "")) } else { texts := util.TrimmedTexts(cols) assign := &model.Assignment{ Id: id, CourseId: courseId, BeginAt: texts[1], DueAt: texts[2] + "T23:59:59+0800", Title: texts[0], } switch subStatus := texts[3]; subStatus { case "尚未提交": case "已经提交": assign.Submission = new(model.Submission) default: errMsg = fmt.Errorf("Unknown submission status: %s", subStatus) } assignments[i] = assign } return errMsg == nil }) if errMsg != nil { status = http.StatusInternalServerError errMsg = fmt.Errorf("Failed to parse %s: %s", url, errMsg) return } return }
func (ada *Adapter) AnnouncementList(courseId string) (announcements []*model.Announcement, status int, errMsg error) { status = http.StatusOK url := AnnouncementListURL(courseId) doc, err := ada.GetDocument(url) if err != nil { status = http.StatusBadGateway errMsg = err return } rows := doc.Find("#table_box tr~tr") announcements = make([]*model.Announcement, rows.Size()) rows.EachWithBreak(func(i int, s *goquery.Selection) bool { if cols := s.Children(); cols.Size() != 5 { errMsg = fmt.Errorf("Expect 5 columns, got %d.", cols.Size()) } else if link := cols.Eq(1).Find("a"); link.Size() == 0 { errMsg = fmt.Errorf("Failed to find link in column 1.") } else if _, id := ParseAnnouncementURL(link.AttrOr("href", "")); id == "" { errMsg = fmt.Errorf("Failed to find announcement id from href (%s).", link.AttrOr("href", "")) } else { texts := util.TrimmedTexts(cols) annc := &model.Announcement{ Id: id, CourseId: courseId, Owner: &model.User{Name: strings.TrimSuffix(texts[2], "老师")}, CreatedAt: texts[3], Title: texts[1], } if red := link.Find("font[color=red]"); red.Size() > 0 { annc.Priority = 1 } announcements[i] = annc } return errMsg == nil }) if errMsg != nil { status = http.StatusInternalServerError errMsg = fmt.Errorf("Failed to parse %s: %s", url, errMsg) return } return }
func (ada *Adapter) Files(courseId string) (files []*model.File, status int, errMsg error) { // TODO: Clean this function up. files = make([]*model.File, 0) url := FilesURL(courseId) doc, err := ada.GetDocument(url) if err != nil { status = http.StatusBadGateway errMsg = err return } // Find all categories. categories := util.TrimmedTexts(doc.Find("#table_box td.textTD")) doc.Find("div.layerbox").EachWithBreak(func(i int, div *goquery.Selection) bool { if i >= len(categories) { return false } category := []string{categories[i]} div.Find("#table_box tr~tr").EachWithBreak(func(_ int, s *goquery.Selection) bool { if cols := s.Children(); cols.Size() != 6 { errMsg = fmt.Errorf("Expect 6 columns, got %d.", cols.Size()) } else if link := cols.Eq(1).Find("a"); link.Size() == 0 { errMsg = fmt.Errorf("Failed to find link in column 1.") } else if _, id := ParseDownloadURL(link.AttrOr("href", "")); id == "" { errMsg = fmt.Errorf("Failed to find file id from href (%s).", link.AttrOr("href", "")) } else { texts := util.TrimmedTexts(cols) file := &model.File{ Id: id, CourseId: courseId, CreatedAt: texts[4], Title: texts[1], Description: texts[2], Category: category, DownloadURL: BaseURL + link.AttrOr("href", ""), } files = append(files, file) } return errMsg == nil }) return errMsg == nil }) if errMsg != nil { status = http.StatusInternalServerError errMsg = fmt.Errorf("Failed to parse %s: %s", url, errMsg) return } // Fill file infos. sg := util.NewStatusGroup() for _, file := range files { file := file sg.Go(func(status *int, err *error) { file.Filename, file.Size, *status, *err = ada.FileInfo(file.DownloadURL, simplifiedchinese.GBK) }) } status, errMsg = sg.Wait() return }