// RequestRandomGroupHandler is a http handler used by a student to request a random group assignment. func RequestRandomGroupHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkMemberApproval(w, r, false) if err != nil { http.Error(w, err.Error(), 404) log.Println(err) return } orgname := r.FormValue("course") if !git.HasOrganization(orgname) { http.Error(w, "Does not have organization.", 404) } org, err := git.NewOrganization(orgname, false) if err != nil { http.Error(w, "Does not have organization.", 404) } defer func() { err := org.Save() if err != nil { org.Unlock() log.Println(err) } }() org.PendingRandomGroup[member.Username] = nil }
// AddAssistantHandler is a http handler used to add users as assistants on a course. func AddAssistantHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, false) if err != nil { log.Println(err) return } username := r.FormValue("assistant") course := r.FormValue("course") if !git.HasOrganization(course) { http.Error(w, "Unknown course.", 404) return } if username == member.Username { return } assistant, err := git.NewMemberFromUsername(username, false) if err != nil { http.Error(w, err.Error(), 500) return } defer func() { if err := assistant.Save(); err != nil { assistant.Unlock() log.Println(err) } }() org, err := git.NewOrganization(course, false) if err != nil { http.Error(w, err.Error(), 500) return } defer func() { if err := org.Save(); err != nil { org.Unlock() log.Println(err) } }() if !org.IsTeacher(member) { http.Error(w, "User is not the teacher for this course.", 404) return } assistant.AddAssistingOrganization(org) org.AddTeacher(assistant) if _, ok := org.PendingUser[username]; ok { delete(org.PendingUser, username) } }
// RemoveUserHandler is http handler used to remove users from the list of students on a course. func RemoveUserHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { http.Redirect(w, r, "/", 307) log.Println(err) return } username := r.FormValue("user") course := r.FormValue("course") if !git.HasOrganization(course) { http.Error(w, "Unknown course.", 404) return } org, err := git.NewOrganization(course, false) if err != nil { http.Error(w, "Not valid organization.", 404) return } defer func() { err := org.Save() if err != nil { org.Unlock() log.Println(err) } }() if !org.IsTeacher(member) { http.Error(w, "Is not a teacher or assistant for this course.", 404) return } user, err := git.NewMemberFromUsername(username, false) if err != nil { http.Error(w, err.Error(), 500) return } defer func() { err := user.Save() if err != nil { user.Unlock() log.Println(err) } }() if org.IsMember(user) { org.RemoveMembership(user) user.RemoveOrganization(org) } else { http.Error(w, "Couldn't find this user in this course. ", 404) return } }
// RegisterCourseMemberHandler is a http handler which register new students // signing up for a course. After registering the student, this handler // gives back a informal page about how to accept the invitation to the // organization on github. func RegisterCourseMemberHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkMemberApproval(w, r, true) if err != nil { log.Println(err) return } // Gets the org and check if valid orgname := "" if path := strings.Split(r.URL.Path, "/"); len(path) == 4 { if !git.HasOrganization(path[3]) { http.Redirect(w, r, "/course/register", 307) return } orgname = path[3] } else { http.Redirect(w, r, "/course/register", 307) return } org, err := git.NewOrganization(orgname, false) if err != nil { http.Redirect(w, r, "/course/register", 307) return } defer func() { err = org.Save() if err != nil { org.Unlock() log.Println(err) } }() if _, ok := org.Members[member.Username]; ok { http.Redirect(w, r, "/course/"+orgname, 307) return } err = org.AddMembership(member) if err != nil { log.Println("Error adding the student to course. Error msg:", err) } view := NewMemberView{ StdTemplate: StdTemplate{ Member: member, }, Org: orgname, } execTemplate("course-registeredmemberinfo.html", w, view) }
// ListReviewsHandler will write back a list of all the code reviews // in a course, as json data. // // Expected input keys: course func ListReviewsHandler(w http.ResponseWriter, r *http.Request) { view := ListReviewsView{ Error: true, } enc := json.NewEncoder(w) // Checks if the user is signed in. member, err := checkMemberApproval(w, r, true) if err != nil { log.Println(err) return } if r.FormValue("course") == "" { view.Errormsg = "Missing required course field." enc.Encode(view) return } if !git.HasOrganization(r.FormValue("course")) { view.Errormsg = "Unknown course." enc.Encode(view) return } org, err := git.NewOrganization(r.FormValue("course"), true) if err != nil { view.Errormsg = "Unknown course." enc.Encode(view) return } if !org.IsMember(member) { view.Errormsg = "Not a member of this course." enc.Encode(view) return } crlist := []*git.CodeReview{} for _, crid := range org.CodeReviewlist { if cr, err := git.GetCodeReview(crid); err == nil { crlist = append(crlist, cr) } } view.Error = false view.Reviews = crlist enc.Encode(view) }
// RemovePendingUserHandler is http handler used to remove users from the list of pending students on a course. func RemovePendingUserHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { http.Redirect(w, r, "/", 307) log.Println(err) return } username := r.FormValue("user") course := r.FormValue("course") if !git.HasOrganization(course) { http.Error(w, "Unknown course.", 404) return } org, err := git.NewOrganization(course, false) if err != nil { http.Error(w, "Not valid organization.", 404) return } defer func() { err := org.Save() if err != nil { org.Unlock() log.Println(err) } }() org.Lock() defer org.Unlock() if !org.IsTeacher(member) { http.Error(w, "Is not a teacher or assistant for this course.", 404) return } if _, ok := org.PendingUser[username]; ok { delete(org.PendingUser, username) } }
// ScoreboardHandler is a http handler to give the user a page // showing the scoreboard for a course func ScoreboardHandler(w http.ResponseWriter, r *http.Request) { member, err := checkMemberApproval(w, r, true) if err != nil { return } // Gets the org and check if valid orgname := "" if path := strings.Split(r.URL.Path, "/"); len(path) == 3 { if !git.HasOrganization(path[2]) { http.Redirect(w, r, HomeURL, 307) return } orgname = path[2] } else { http.Redirect(w, r, HomeURL, 307) return } org, err := git.NewOrganization(orgname, true) if err != nil { http.Error(w, err.Error(), 500) return } if !org.IsMember(member) { http.Redirect(w, r, HomeURL, 307) return } view := ScoreboardView{ StdTemplate: StdTemplate{ Member: member, }, Org: org, } execTemplate("scoreboard.html", w, view) }
// UserCoursePageHandler is a http handler giving back the main user // page for a course. This page gived information about all the labs // and results for a user. A user can also submit code reviews from // this page. func UserCoursePageHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in. member, err := checkMemberApproval(w, r, true) if err != nil { log.Println(err) return } // Gets the org and check if valid orgname := "" if path := strings.Split(r.URL.Path, "/"); len(path) == 3 { if !git.HasOrganization(path[2]) { http.Redirect(w, r, pages.HOMEPAGE, 307) return } orgname = path[2] } else { http.Redirect(w, r, pages.HOMEPAGE, 307) return } org, err := git.NewOrganization(orgname, true) if err != nil { http.Redirect(w, r, pages.HOMEPAGE, 307) return } view := MainCourseView{ StdTemplate: StdTemplate{ Member: member, }, Org: org, } nr := member.Courses[org.Name].CurrentLabNum if nr >= org.IndividualAssignments { view.Labnum = org.IndividualAssignments - 1 } else { view.Labnum = nr - 1 } if member.Courses[orgname].IsGroupMember { group, err := git.NewGroup(orgname, member.Courses[orgname].GroupNum, true) if err != nil { log.Println(err) return } if group.Course != orgname { member.Lock() opt := member.Courses[orgname] opt.IsGroupMember = false opt.GroupNum = 0 member.Courses[orgname] = opt err = member.Save() if err != nil { log.Println(err) member.Unlock() } } view.Group = group if group.CurrentLabNum >= org.GroupAssignments { view.GroupLabnum = org.GroupAssignments - 1 } else { view.GroupLabnum = group.CurrentLabNum - 1 } } execTemplate("maincoursepage.html", w, view) }
// ApproveCourseMembershipHandler is a http handler used when a teacher wants // to accept a student for a course in autograder. This handler will link the // student to the course organization on github and also create all the needed // repositories on github. func ApproveCourseMembershipHandler(w http.ResponseWriter, r *http.Request) { enc := json.NewEncoder(w) view := ApproveMembershipView{} view.Error = true // default is an error; if its not we anyway set it to false before encoding // Checks if the user is signed in and a teacher. /*member*/ _, err := checkTeacherApproval(w, r, false) if err != nil { log.Println(err) view.ErrorMsg = "You are not singed in or not a teacher." enc.Encode(view) return } // Gets the org and check if valid orgname := "" if path := strings.Split(r.URL.Path, "/"); len(path) == 4 { if !git.HasOrganization(path[3]) { http.Redirect(w, r, pages.HOMEPAGE, 307) return } orgname = path[3] } else { http.Redirect(w, r, pages.HOMEPAGE, 307) return } username := r.FormValue("user") if username == "" { view.ErrorMsg = "Username was not set in the request." enc.Encode(view) return } org, err := git.NewOrganization(orgname, false) if err != nil { view.ErrorMsg = "Could not retrieve the stored organization." enc.Encode(view) return } defer func() { err := org.Save() if err != nil { org.Unlock() log.Println(err) } }() teams, err := org.ListTeams() if err != nil { log.Println(err) view.ErrorMsg = "Error communicating with Github. Can't get list teams." enc.Encode(view) return } if org.IndividualAssignments > 0 { repo := git.RepositoryOptions{ Name: username + "-" + git.StandardRepoName, Private: org.Private, AutoInit: true, Issues: true, Hook: "*", } err = org.CreateRepo(repo) if err != nil { log.Println(err) view.ErrorMsg = "Error communicating with Github. Couldn't create repository." enc.Encode(view) return } if t, ok := teams[username]; !ok { newteam := git.TeamOptions{ Name: username, Permission: git.PushPermission, RepoNames: []string{username + "-" + git.StandardRepoName}, } teamID, err := org.CreateTeam(newteam) if err != nil { log.Println(err) view.ErrorMsg = "Error communicating with Github. Can't create team." enc.Encode(view) return } err = org.AddMemberToTeam(teamID, username) if err != nil { log.Println(err) view.ErrorMsg = "Error communicating with Github. Can't add member to team." enc.Encode(view) return } } else { err = org.LinkRepoToTeam(t.ID, username+"-"+git.StandardRepoName) if err != nil { log.Println(err) view.ErrorMsg = "Error communicating with Github. Can't link repo to team." enc.Encode(view) return } err = org.AddMemberToTeam(t.ID, username) if err != nil { log.Println(err) view.ErrorMsg = "Error communicating with Github. Can't add member to team." enc.Encode(view) return } } } delete(org.PendingUser, username) org.Members[username] = nil member, err := git.NewMemberFromUsername(username, false) if err != nil { view.ErrorMsg = "Could not retrieve the stored user." enc.Encode(view) return } defer func() { err = member.Save() if err != nil { member.Unlock() log.Println(err) } }() member.AddOrganization(org) view.Error = false // it wasn't an error after all view.Approved = true view.User = username enc.Encode(view) }
// LeaderboardDataHandler is a http handler which return the leaderboard for a course in JSON format. func LeaderboardDataHandler(w http.ResponseWriter, r *http.Request) { view := LeaderboardDataView{} view.Error = true enc := json.NewEncoder(w) member, err := checkMemberApproval(w, r, true) if err != nil { enc.Encode(ErrAccessToken) return } orgname := r.FormValue("course") period, err := strconv.Atoi(r.FormValue("period")) if err != nil { enc.Encode(ErrMissingField) return } if !git.HasOrganization(orgname) { enc.Encode(ErrUnknownCourse) return } org, err := git.NewOrganization(orgname, true) if err != nil { view.ErrorMsg = err.Error() enc.Encode(view) return } if !org.IsMember(member) { enc.Encode(ErrNotMember) return } var t time.Time if period == TotalScore { view.Error = false view.Leaderboard = org.GetTotalLeaderboard() view.Scores = org.TotalScore } else if period == MonthlyScore { t, err = time.Parse("1", r.FormValue("month")) if err != nil { t = time.Now() } month := t.Month() view.Error = false view.Leaderboard = org.GetMonthlyLeaderboard(month) view.Scores = org.MonthlyScore[month] } else if period == WeeklyScore { week, err := strconv.Atoi(r.FormValue("week")) if err != nil { _, week = time.Now().ISOWeek() } if week < 1 || week > 53 { view.ErrorMsg = "Week need to be between 1 and 53." enc.Encode(view) return } view.Error = false view.Leaderboard = org.GetWeeklyLeaderboard(week) view.Scores = org.WeeklyScore[week] } enc.Encode(view) }
// ApManualTestHandler is a http handler for manually triggering // anti-plagiarism tests. func ApManualTestHandler(w http.ResponseWriter, r *http.Request) { if !git.HasOrganization(r.FormValue("course")) { http.Error(w, "Unknown organization", 404) log.Println("Unknown organization") return } org, err := git.NewOrganization(r.FormValue("course"), true) if err != nil { http.Error(w, "Organization Error", 404) log.Println(err) return } var labs []*apProto.ApRequestLab var repos []string isGroup := false if strings.Contains(r.FormValue("labs"), "group") { // Get the information for groups isGroup = true length := len(org.GroupLabFolders) for i := 1; i <= length; i++ { if org.GroupLabFolders[i] != "" { labs = append(labs, &apProto.ApRequestLab{Name: org.GroupLabFolders[i], Language: org.GroupLanguages[i]}) } } // The order of the repos does not matter. for groupName := range org.Groups { repos = append(repos, groupName) } } else { // Get the information for individuals isGroup = false length := len(org.IndividualLabFolders) for i := 1; i <= length; i++ { if org.IndividualLabFolders[i] != "" { labs = append(labs, &apProto.ApRequestLab{Name: org.IndividualLabFolders[i], Language: org.IndividualLanguages[i]}) } } // The order of the repos does not matter. for indvName := range org.Members { repos = append(repos, indvName+"-labs") } } // Create request request := apProto.ApRequest{GithubOrg: org.Name, GithubToken: org.AdminToken, StudentRepos: repos, Labs: labs} go callAntiplagiarism(request, org, isGroup) fmt.Printf("%v\n", request) }
// TeachersPanelHandler is a http handler serving the Teacher panel. // This page shows a summary of all the students and groups. func TeachersPanelHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { log.Println(err) http.Redirect(w, r, pages.HOMEPAGE, 307) return } // Gets the org and check if valid orgname := "" if path := strings.Split(r.URL.Path, "/"); len(path) == 4 { if !git.HasOrganization(path[3]) { http.Redirect(w, r, pages.HOMEPAGE, 307) return } orgname = path[3] } else { http.Redirect(w, r, pages.HOMEPAGE, 307) return } org, err := git.NewOrganization(orgname, true) if err != nil { http.Error(w, err.Error(), 500) return } if !org.IsTeacher(member) { log.Println("User is not a teacher for this course.") http.Redirect(w, r, pages.HOMEPAGE, 307) return } // gets pending users users := org.PendingUser var status string for username := range users { // check status up against Github users[username], err = git.NewMemberFromUsername(username, true) if err != nil { continue } status, err = org.GetMembership(users[username].(*git.Member)) if err != nil { log.Println(err) continue } if status == "active" { continue // TODO: what about group assignments? } else if status == "pending" { delete(users, username) } else { delete(users, username) log.Println("Got a unexpected status back from Github regarding Membership") } } // gets teachers for username := range org.Teachers { org.Teachers[username], _ = git.NewMemberFromUsername(username, true) } // gets users for username := range org.Members { org.Members[username], _ = git.NewMemberFromUsername(username, true) } // get pending groups pendinggroups := make(map[int]*git.Group) for groupID := range org.PendingGroup { group, err := git.NewGroup(org.Name, groupID, true) if err != nil { log.Println(err) } if group.Course != org.Name { org.Lock() delete(org.PendingGroup, groupID) err := org.Save() if err != nil { log.Println(err) org.Unlock() } continue } for key := range group.Members { groupmember, _ := git.NewMemberFromUsername(key, true) group.Members[key] = groupmember } pendinggroups[groupID] = group } // get groups for groupname := range org.Groups { groupID, _ := strconv.Atoi(groupname[5:]) group, _ := git.NewGroup(org.Name, groupID, true) for key := range group.Members { groupmember, _ := git.NewMemberFromUsername(key, true) group.Members[key] = groupmember } org.Groups[groupname] = group } _, _, labtype := org.FindCurrentLab() view := TeachersPanelView{ StdTemplate: StdTemplate{ Member: member, }, PendingUser: users, Org: org, PendingGroup: pendinggroups, CurrentLabType: labtype, } execTemplate("teacherspanel.html", w, view) }
// ShowResultHandler is a http handler for showing a page detailing // lab resutls for a single user or group. func ShowResultHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { return } // Gets the org and check if valid orgname := "" if path := strings.Split(r.URL.Path, "/"); len(path) == 4 { if !git.HasOrganization(path[3]) { http.Redirect(w, r, pages.HOMEPAGE, 307) return } orgname = path[3] } else { http.Redirect(w, r, pages.HOMEPAGE, 307) return } username := r.FormValue("user") if username == "" { http.Redirect(w, r, pages.HOMEPAGE, 307) return } if !git.HasOrganization(orgname) { http.Redirect(w, r, pages.HOMEPAGE, 307) return } org, err := git.NewOrganization(orgname, true) if err != nil { http.Error(w, err.Error(), 500) } isgroup := false groupid := -1 labnum := 0 if !git.HasMember(username) { groupnum, err := strconv.Atoi(username[len("group"):]) if err != nil { http.Redirect(w, r, pages.HOMEPAGE, 307) return } if git.HasGroup(groupnum) { isgroup = true group, err := git.NewGroup(org.Name, groupnum, true) if err != nil { http.Redirect(w, r, pages.HOMEPAGE, 307) return } groupid = group.ID if group.CurrentLabNum >= org.GroupAssignments { labnum = org.GroupAssignments } else { labnum = group.CurrentLabNum } } else { http.Redirect(w, r, pages.HOMEPAGE, 307) return } } else { user, err := git.NewMemberFromUsername(username, true) if err != nil { http.Error(w, err.Error(), 500) } nr := user.Courses[org.Name].CurrentLabNum if nr >= org.IndividualAssignments { labnum = org.IndividualAssignments } else { labnum = nr } } view := ShowResultView{ StdTemplate: StdTemplate{ Member: member, }, Org: org, Username: username, Labnum: labnum, IsGroup: isgroup, GroupID: groupid, } execTemplate("teacherresultpage.html", w, view) }
// AddGroupMemberHandler is a http handler adding an additional member to a active group. func AddGroupMemberHandler(w http.ResponseWriter, r *http.Request) { view := AddGroupMemberView{} view.Error = true enc := json.NewEncoder(w) // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { err = enc.Encode(ErrSignIn) return } orgname := r.FormValue("course") if orgname == "" || !git.HasOrganization(orgname) { err = enc.Encode(ErrUnknownCourse) return } groupid, err := strconv.Atoi(r.FormValue("groupid")) if err != nil { view.ErrorMsg = err.Error() err = enc.Encode(view) return } if !git.HasGroup(groupid) { err = enc.Encode(ErrUnknownGroup) return } org, err := git.NewOrganization(orgname, false) if err != nil { view.ErrorMsg = err.Error() err = enc.Encode(view) return } defer func() { err := org.Save() if err != nil { org.Unlock() log.Println(err) } }() if !org.IsTeacher(member) { err = enc.Encode(ErrNotTeacher) return } group, err := git.NewGroup(orgname, groupid, false) if err != nil { view.ErrorMsg = err.Error() err = enc.Encode(view) return } defer func() { err := group.Save() if err != nil { group.Unlock() log.Println(err) } }() if group.TeamID == 0 { teams, err := org.ListTeams() if err != nil { view.ErrorMsg = err.Error() err = enc.Encode(view) return } if team, ok := teams[git.GroupRepoPrefix+strconv.Itoa(groupid)]; ok { group.TeamID = team.ID } else { view.ErrorMsg = "Error finding team on GitHub." err = enc.Encode(view) return } } r.ParseForm() members := r.PostForm["member"] for _, username := range members { if username == "" || !git.HasMember(username) { continue } group.AddMember(username) org.AddMemberToTeam(group.TeamID, username) delete(org.PendingRandomGroup, username) } group.Activate() view.Added = true view.Error = false enc.Encode(view) }
// RemovePendingGroupHandler is used to remove a group. func RemovePendingGroupHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { http.Redirect(w, r, "/", 307) log.Println(err) return } groupid, err := strconv.Atoi(r.FormValue("groupid")) if err != nil { http.Error(w, "Group ID is not a number: "+err.Error(), 404) return } course := r.FormValue("course") if !git.HasOrganization(course) { http.Error(w, "Unknown course.", 404) return } org, err := git.NewOrganization(course, false) if err != nil { http.Error(w, "Unknown course.", 404) return } defer func() { err := org.Save() if err != nil { org.Unlock() log.Println(err) } }() if !org.IsTeacher(member) { http.Error(w, "Is not a teacher or assistant for this course.", 404) return } if !git.HasGroup(groupid) { groupname := git.GroupRepoPrefix + strconv.Itoa(groupid) if _, ok := org.Groups[groupname]; ok { delete(org.Groups, groupname) return } http.Error(w, "Unknown group.", 404) return } if _, ok := org.PendingGroup[groupid]; ok { delete(org.PendingGroup, groupid) } groupname := git.GroupRepoPrefix + strconv.Itoa(groupid) if _, ok := org.Groups[groupname]; ok { delete(org.Groups, groupname) } group, err := git.NewGroup(org.Name, groupid, false) if err != nil { http.Error(w, "Could not get the group: "+err.Error(), 404) return } group.Delete() }
// ManualCITriggerHandler is a http handler for manually triggering test builds. func ManualCITriggerHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkMemberApproval(w, r, false) if err != nil { http.Error(w, err.Error(), 404) log.Println(err) return } course := r.FormValue("course") user := r.FormValue("user") lab := r.FormValue("lab") if !git.HasOrganization(course) { http.Error(w, "Unknown organization", 404) return } org, err := git.NewOrganization(course, true) if err != nil { http.Error(w, "Organization Error", 404) return } // Defaults back to username or group name for the user if not a teacher. if !org.IsTeacher(member) { if org.IsMember(member) { if strings.Contains(user, "group") { if member.Courses[org.Name].IsGroupMember { user = "******" + strconv.Itoa(member.Courses[org.Name].GroupNum) } else { http.Error(w, "Not a group member", 404) return } } else { user = member.Username } } else { http.Error(w, "Not a member of the course", 404) return } } groupid := -1 labnum := -1 if strings.Contains(user, "group") { groupid, err = strconv.Atoi(user[len("group"):]) if err != nil { http.Error(w, err.Error(), 500) return } for i, name := range org.GroupLabFolders { if name == lab { labnum = i break } } } else { for i, name := range org.IndividualLabFolders { if name == lab { labnum = i break } } } var repo string var destfolder string if _, ok := org.Members[user]; ok { repo = user + "-" + git.StandardRepoName destfolder = git.StandardRepoName } else if _, ok := org.Groups[user]; ok { repo = user destfolder = git.GroupsRepoName } else { http.Error(w, "Unknown user", 404) return } opt := ci.DaemonOptions{ Org: org.Name, User: user, Group: groupid, Repo: repo, BaseFolder: org.CI.Basepath, LabFolder: lab, LabNumber: labnum, AdminToken: org.AdminToken, DestFolder: destfolder, Secret: org.CI.Secret, IsPush: false, } log.Println(opt) ci.StartTesterDaemon(opt) }
// PublishReviewHandler is a http handler which will publish a new // code review to github. The function output json as the answer. // // Expected input keys: course, title, fileext, desc and code. func PublishReviewHandler(w http.ResponseWriter, r *http.Request) { view := PublishReviewView{ Error: true, } enc := json.NewEncoder(w) // Checks if the user is signed in. member, err := checkMemberApproval(w, r, true) if err != nil { view.Errormsg = "Not logged in." enc.Encode(view) return } if r.FormValue("course") == "" || r.FormValue("title") == "" || r.FormValue("fileext") == "" || r.FormValue("desc") == "" || r.FormValue("code") == "" { view.Errormsg = "Missing some required input data." enc.Encode(view) return } if !git.HasOrganization(r.FormValue("course")) { view.Errormsg = "Unknown course." enc.Encode(view) return } org, err := git.NewOrganization(r.FormValue("course"), false) if err != nil { view.Errormsg = "Error while getting orgaization data from storage." enc.Encode(view) return } defer func() { if err := org.Save(); err != nil { org.Unlock() log.Println(err) } }() if !org.IsMember(member) { view.Errormsg = "Not a member of this course." enc.Encode(view) return } alfanumreg, err := regexp.Compile("[^A-Za-z0-9]+") if err != nil { view.Errormsg = "Internal sanitazion error." enc.Encode(view) return } reg, err := regexp.Compile("[^A-Za-z0-9 -.]+") if err != nil { view.Errormsg = "Internal sanitazion error." enc.Encode(view) return } // removes illigal chars ext := r.FormValue("fileext") ext = alfanumreg.ReplaceAllString(ext, "") ext = strings.TrimSpace(ext) title := r.FormValue("title") title = reg.ReplaceAllString(title, "") title = strings.TrimSpace(title) cr, err := git.NewCodeReview() if err != nil { view.Errormsg = "Couldn't create code review: " + err.Error() enc.Encode(view) return } cr.Title = title cr.Ext = ext cr.Desc = r.FormValue("desc") cr.Code = r.FormValue("code") cr.User = member.Username err = org.AddCodeReview(cr) if err != nil { view.Errormsg = err.Error() enc.Encode(view) return } if err := cr.Save(); err != nil { view.Errormsg = err.Error() enc.Encode(view) return } view.Error = false view.CommitURL = cr.URL enc.Encode(view) }
// ApproveLabHandler is a http handler used by teachers to approve a lab. func ApproveLabHandler(w http.ResponseWriter, r *http.Request) { // Checks if the user is signed in and a teacher. member, err := checkTeacherApproval(w, r, true) if err != nil { log.Println(err) return } course := r.FormValue("Course") username := r.FormValue("User") approve := r.FormValue("Approve") labnum, err := strconv.Atoi(r.FormValue("Labnum")) if err != nil { log.Println(err) http.Error(w, err.Error(), 404) return } if approve != "true" { log.Println("Missing approval") http.Error(w, "Not approved", 404) return } if !git.HasOrganization(course) || username == "" { log.Println("Missing username or uncorrect course") http.Error(w, "Unknown Organization", 404) return } org, err := git.NewOrganization(course, true) if err != nil { log.Println(err) http.Error(w, err.Error(), 404) return } if !org.IsTeacher(member) { log.Println(member.Name + " is not a teacher of " + org.Name) http.Error(w, "Not a teacher of this course.", 404) return } var isgroup bool if git.HasMember(username) { isgroup = false } else { isgroup = strings.Contains(username, "group") if !isgroup { log.Println("No user found") http.Error(w, "Unknown User", 404) return } } var latestbuild int var res *ci.BuildResult if isgroup { gnum, err := strconv.Atoi(username[len("group"):]) if err != nil { log.Println(err) http.Error(w, err.Error(), 404) return } group, err := git.NewGroup(course, gnum, false) if err != nil { log.Println(err) http.Error(w, err.Error(), 404) return } defer func() { if err := group.Save(); err != nil { group.Unlock() log.Println(err) } }() latestbuild = group.GetLastBuildID(labnum) if latestbuild < 0 { http.Error(w, "No build registered on lab.", 500) return } res, err = ci.GetBuildResult(latestbuild) if err != nil { log.Println(err) http.Error(w, err.Error(), 500) return } group.SetApprovedBuild(res.Labnum, res.ID, res.PushTime) if org.Slipdays { for username := range group.Members { user, err := git.NewMemberFromUsername(username, false) if err != nil { log.Println(err) continue } copt := user.Courses[org.Name] err = copt.RecalculateSlipDays() if err != nil { log.Println(err) } user.Courses[org.Name] = copt } } } else { user, err := git.NewMemberFromUsername(username, false) if err != nil { log.Println(err.Error()) http.Error(w, err.Error(), 500) return } defer func() { if err := user.Save(); err != nil { user.Unlock() log.Println(err) } }() latestbuild = user.GetLastBuildID(course, labnum) if latestbuild < 0 { http.Error(w, "No build registered on lab.", 500) return } res, err = ci.GetBuildResult(latestbuild) if err != nil { log.Println(err) http.Error(w, err.Error(), 500) return } user.SetApprovedBuild(org.Name, res.Labnum, res.ID, res.PushTime) if org.Slipdays { copt := user.Courses[org.Name] err = copt.RecalculateSlipDays() if err != nil { log.Println(err) } user.Courses[org.Name] = copt } } res.Status = "Approved" if err := res.Save(); err != nil { log.Println(err) http.Error(w, err.Error(), 500) return } }
// StartTestBuildProcess will use the payload from github to start the ci build. func StartTestBuildProcess(load github.PushPayload) (err error) { userlogin := *load.Pusher.Name reponame := *load.Repo.Name orgname := *load.Organization.Login if !git.HasMember(userlogin) { log.Println("Not a valid user: "******"Not a valid org: ", orgname) return errors.New("Not a valid org: " + orgname) } org, err := git.NewOrganization(orgname, true) user, err := git.NewMemberFromUsername(userlogin, true) isgroup := !strings.Contains(reponame, "-"+git.StandardRepoName) var labfolder string var destfolder string var labnum int var username string var gnum = -1 if isgroup { gnum, err = strconv.Atoi(reponame[len("group"):]) if err != nil { log.Println(err) return err } group, err := git.NewGroup(org.Name, gnum, true) if err != nil { log.Println(err) return err } labnum = group.CurrentLabNum if labnum > org.GroupAssignments { labnum = org.GroupAssignments } labfolder = org.GroupLabFolders[labnum] username = reponame destfolder = git.GroupsRepoName } else { labnum = user.Courses[org.Name].CurrentLabNum if labnum > org.IndividualAssignments { labnum = org.IndividualAssignments } labfolder = org.IndividualLabFolders[labnum] username = strings.TrimRight(reponame, "-"+git.StandardRepoName) destfolder = git.StandardRepoName } opt := ci.DaemonOptions{ Org: org.Name, User: username, Group: gnum, Repo: reponame, BaseFolder: org.CI.Basepath, LabFolder: labfolder, LabNumber: labnum, AdminToken: org.AdminToken, DestFolder: destfolder, IsPush: true, Secret: org.CI.Secret, } go ci.StartTesterDaemon(opt) return }