Beispiel #1
0
// 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
}
Beispiel #2
0
// 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)
	}
}
Beispiel #3
0
// 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
	}
}
Beispiel #4
0
// 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)
}
Beispiel #5
0
// 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)
}
Beispiel #6
0
// 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)
	}
}
Beispiel #7
0
// 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)
}
Beispiel #8
0
// 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)
}
Beispiel #9
0
// 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)
}
Beispiel #10
0
// 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)
}
Beispiel #11
0
// 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)
}
Beispiel #12
0
// 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)
}
Beispiel #13
0
// 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)
}
Beispiel #14
0
// 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)
}
Beispiel #15
0
// 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()
}
Beispiel #16
0
// 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)
}
Beispiel #17
0
// 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)
}
Beispiel #18
0
// 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
	}
}
Beispiel #19
0
// 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
}