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 New(userId, password string) (ada *Adapter, status int, errMsg error) { ada = new(Adapter) sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { ada.Adapter, *status, *err = cic.New(userId, password) }) sg.Go(func(status *int, err *error) { ada.Old, *status, *err = old.New(userId, password) }) status, errMsg = sg.Wait() return }
func (ada *Adapter) AllAttended(english bool) (courses []*model.Course, status int, errMsg error) { var pastCourses, thisCourses, nextCourses []*model.Course sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { thisCourses, nextCourses, *status, *err = ada.NowAttended(english) }) sg.Go(func(status *int, err *error) { pastCourses, *status, *err = ada.PastAttended(english) }) status, errMsg = sg.Wait() courses = append(nextCourses, thisCourses...) courses = append(courses, pastCourses...) return }
func (ada *Adapter) AllAttendedList() (courses []*model.Course, status int, errMsg error) { var thisCourses, pastCourses []*model.Course sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { thisCourses, *status, *err = ada.AttendedList(1) }) sg.Go(func(status *int, err *error) { pastCourses, *status, *err = ada.AttendedList(2) }) status, errMsg = sg.Wait() courses = append(thisCourses, pastCourses...) return }
func (ada *Adapter) Attended(semesterId string, english bool) (courses []*model.Course, status int, errMsg error) { var m map[fatName]string sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { m, *status, *err = ada.nameIdMap() }) sg.Go(func(status *int, err *error) { courses, *status, *err = ada.Adapter.Attended(semesterId, english) }) if status, errMsg = sg.Wait(); errMsg == nil { replaceCourseIds(courses, m) } return }
func (ada *Adapter) Announcements(courseId string) (announcements []*model.Announcement, status int, errMsg error) { if announcements, status, errMsg = ada.AnnouncementList(courseId); errMsg != nil { return } sg := util.NewStatusGroup() for _, annc := range announcements { annc := annc sg.Go(func(status *int, err *error) { _, annc.Body, annc.Owner.Email, *status, *err = ada.Announcement(courseId, annc.Id) }) } status, errMsg = sg.Wait() return }
func (ada *Adapter) NowAttended(english bool) (thisCourses []*model.Course, nextCourses []*model.Course, status int, errMsg error) { var m map[fatName]string sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { m, *status, *err = ada.nameIdMap() }) sg.Go(func(status *int, err *error) { thisCourses, nextCourses, *status, *err = ada.Adapter.NowAttended(english) }) if status, errMsg = sg.Wait(); errMsg == nil { replaceCourseIds(thisCourses, m) replaceCourseIds(nextCourses, m) } return }
func (ada *Adapter) NowAttended(english bool) (thisCourses []*model.Course, nextCourses []*model.Course, status int, errMsg error) { var thisSem, nextSem *model.Semester thisSem, nextSem, status, errMsg = ada.Semesters() if errMsg != nil { return } sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { thisCourses, *status, *err = ada.Attended(thisSem.Id, english) }) sg.Go(func(status *int, err *error) { nextCourses, *status, *err = ada.Attended(nextSem.Id, english) }) status, errMsg = sg.Wait() return }
func BatchResourceFunc(argsStr string, f func(string) (interface{}, int, error)) (v interface{}, status int, err error) { args := strings.Split(argsStr, ",") if len(args) == 1 { v, status, err = f(args[0]) } else { list := make([]interface{}, len(args)) sg := util.NewStatusGroup() for i := range args { i := i sg.Go(func(status *int, err *error) { list[i], *status, *err = f(args[i]) }) } status, err = sg.Wait() v = list } return }
func (ada *Adapter) Assignments(courseId string) (assignments []*model.Assignment, status int, errMsg error) { if assignments, status, errMsg = ada.AssignmentList(courseId); errMsg != nil { return } sg := util.NewStatusGroup() for _, assign := range assignments { assign := assign sg.Go(func(status *int, err *error) { _, assign.Body, assign.Attachment, *status, *err = ada.AssignmentDetail(courseId, assign.Id) }) if assign.Submission != nil { sg.Go(func(status *int, err *error) { assign.Submission, *status, *err = ada.Submission(courseId, assign.Id) }) } } status, errMsg = sg.Wait() return }
func (ada *Adapter) Attended(semesterId string, english bool) (courses []*model.Course, status int, errMsg error) { courses = make([]*model.Course, 0) url := AttendedURL(semesterId) var v struct { ResultList []struct { CourseId string Course_no string Course_seq string Course_name string E_course_name string TeacherInfo struct { Id string Name string Email string Phone string Gender string Title string } CodeDepartmentInfo struct { Dwmc string Dwywmc string } SemesterInfo struct { Id string } Detail_c string Detail_e string Credit int Course_time int } } if err := ada.GetJSON(url, &v); err != nil { return nil, http.StatusBadGateway, err } sg := util.NewStatusGroup() for _, result := range v.ResultList { var name, description, department string if english { name = result.E_course_name description = result.Detail_e department = result.CodeDepartmentInfo.Dwywmc } // Fallback to Chinese version. if name == "" { name = result.Course_name } if description == "" { description = result.Detail_c } if department == "" { department = result.CodeDepartmentInfo.Dwmc } course := &model.Course{ Id: result.CourseId, SemesterId: result.SemesterInfo.Id, Number: result.Course_no, Sequence: result.Course_seq, Name: name, Credit: result.Credit, Hour: result.Course_time, Description: description, Teachers: []*model.User{ &model.User{ Id: result.TeacherInfo.Id, Name: result.TeacherInfo.Name, Type: result.TeacherInfo.Title, Department: department, Gender: result.TeacherInfo.Gender, Email: result.TeacherInfo.Email, Phone: result.TeacherInfo.Phone, }, }, } sg.Go(func(status *int, err *error) { course.Schedules, *status, *err = ada.Schedules(course.Id) }) sg.Go(func(status *int, err *error) { course.Assistants, *status, *err = ada.Assistants(course.Id) }) courses = append(courses, course) } status, errMsg = sg.Wait() return }
"github.com/tsinghua-io/api-server/adapter/tsinghua.edu.cn/x/learn" "github.com/tsinghua-io/api-server/model" "github.com/tsinghua-io/api-server/util" "net/http" ) var CourseMaterials = Resource{ "GET": util.AuthNeededHandler(GetCourseMaterials), } var GetCourseMaterials = learn.HandlerFunc(func(rw http.ResponseWriter, req *http.Request, ada *learn.Adapter) { v, status, err := BatchResourceFunc( mux.Vars(req)["id"], func(id string) (interface{}, int, error) { materials := new(model.Materials) sg := util.NewStatusGroup() sg.Go(func(status *int, err *error) { materials.Announcements, *status, *err = ada.Announcements(id) }) sg.Go(func(status *int, err *error) { materials.Files, *status, *err = ada.Files(id) }) sg.Go(func(status *int, err *error) { materials.Assignments, *status, *err = ada.Assignments(id) }) status, err := sg.Wait() return materials, status, err }) util.JSON(rw, v, status, err)
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 }