예제 #1
0
func session(w http.ResponseWriter, r *http.Request) *webapp.Error {
	idString := r.FormValue("id")
	if idString == "" {
		return missingFields(w)
	}
	id, err := strconv.ParseInt(idString, 10, 64)
	if err != nil {
		return invalidData(w, fmt.Sprintf("Couldn't parse %q as ID", idString))
	}
	c := appengine.NewContext(r)
	session, err := classes.SessionWithID(c, id)
	switch err {
	case nil:
		break
	case classes.ErrSessionNotFound:
		return invalidData(w, fmt.Sprintf("No such session"))
	default:
		return webapp.InternalError(fmt.Errorf("failed to find session %d: %s", id, err))
	}
	classList := session.Classes(c)
	sort.Sort(classes.ClassesByStartTime(classList))
	teachers := classes.TeachersByClass(c, classList)
	data := map[string]interface{}{
		"Session":     session,
		"Classes":     classes.GroupedByDay(classList),
		"DaysInOrder": daysInOrder,
		"Teachers":    teachers,
	}
	if err := sessionPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #2
0
func roster(w http.ResponseWriter, r *http.Request) *webapp.Error {
	id, err := strconv.ParseInt(r.FormValue("class"), 10, 64)
	if err != nil {
		return invalidData(w, "Invalid class ID")
	}
	c := appengine.NewContext(r)
	class, err := classes.ClassWithID(c, id)
	if err != nil {
		return invalidData(w, "No such class.")
	}
	acct, ok := userContext(r)
	if !ok {
		return badRequest(w, "Must be logged in.")
	}
	staff, _ := staff.WithID(c, acct.ID)
	if !canViewRoster(staff, acct, class.TeacherEntity(c)) {
		return webapp.UnauthorizedError(fmt.Errorf("only staff or teachers can view rosters"))
	}
	classStudents := students.In(c, class, time.Now())
	sort.Sort(students.ByName(classStudents))
	token, err := storeNewToken(c, acct.ID, "/register/paper")
	if err != nil {
		return webapp.InternalError(fmt.Errorf("Failed to store token: %s", err))
	}
	data := map[string]interface{}{
		"Class":    class,
		"Students": classStudents,
		"Token":    token.Encode(),
	}
	if err := rosterPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #3
0
func registerForSession(w http.ResponseWriter, r *http.Request) *webapp.Error {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method not allowed")
		return nil
	}
	c := appengine.NewContext(r)
	user, class, err := classAndUser(w, r)
	if err != nil {
		return err
	}
	token, ok := checkToken(c, user.ID, r.URL.Path, r.FormValue(auth.TokenFieldName))
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("Invalid auth token"))
	}
	student := students.New(user, class)
	switch err := student.Add(c, time.Now()); err {
	case nil:
		break
	case students.ErrClassIsFull:
		if err := classFullPage.Execute(w, class); err != nil {
			return webapp.InternalError(err)
		}
	default:
		return webapp.InternalError(fmt.Errorf("failed to write student: %s", err))
	}
	token.Delete(c)
	http.Redirect(w, r, "/", http.StatusSeeOther)
	return nil
}
예제 #4
0
func deleteClass(w http.ResponseWriter, r *http.Request) *webapp.Error {
	idString := r.FormValue("class")
	if idString == "" {
		return missingFields(w)
	}
	id, err := strconv.ParseInt(idString, 10, 64)
	if err != nil {
		return invalidData(w, fmt.Sprintf("Invalid class ID"))
	}
	c := appengine.NewContext(r)
	class, err := classes.ClassWithID(c, id)
	switch err {
	case nil:
		break
	case classes.ErrClassNotFound:
		return invalidData(w, "No such class.")
	default:
		return webapp.InternalError(fmt.Errorf("failed to look up class %d: %s", id, err))
	}
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may delete classes"))
	}
	if r.Method == "POST" {
		c.Infof("updating class %d", class.ID)
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		if err := class.Delete(c); err != nil {
			return webapp.InternalError(fmt.Errorf("failed to delete class %d: %s", class.ID, err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token":   token.Encode(),
		"Class":   class,
		"Teacher": class.TeacherEntity(c),
	}
	if err := deleteClassPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #5
0
func class(w http.ResponseWriter, r *http.Request) *webapp.Error {
	id, err := strconv.ParseInt(r.FormValue("id"), 10, 64)
	if err != nil {
		return invalidData(w, "Couldn't parse class ID")
	}
	c := appengine.NewContext(r)
	class, err := classes.ClassWithID(c, id)
	switch err {
	case nil:
		break
	case classes.ErrClassNotFound:
		return invalidData(w, "No such class")
	default:
		return webapp.InternalError(fmt.Errorf("failed to find class %d: %s", id, err))
	}
	teacher := class.TeacherEntity(c)
	data := map[string]interface{}{
		"Class":   class,
		"Teacher": teacher,
	}
	if u := user.Current(c); u != nil {
		switch a, err := maybeOldAccount(c, u); err {
		case nil:
			data["User"] = a
			staffer, _ := maybeOldStaff(c, a, u)
			data["CanViewRoster"] = canViewRoster(staffer, a, teacher)
			sessionToken, err := storeNewToken(c, a.ID, "/register/session")
			if err != nil {
				return webapp.InternalError(fmt.Errorf("failed to store token: %s"))
			}
			data["SessionToken"] = sessionToken.Encode()
			oneDayToken, err := storeNewToken(c, a.ID, "/register/oneday")
			if err != nil {
				return webapp.InternalError(fmt.Errorf("failed to store token: %s"))
			}
			data["OneDayToken"] = oneDayToken.Encode()
			switch student, err := maybeOldStudent(c, a, u, class); err {
			case nil:
				data["Student"] = student
			case students.ErrStudentNotFound:
				break
			default:
				c.Errorf("failed to find student %q in %d: %s", a.ID, class.ID, err)
			}
		case account.ErrUserNotFound:
			break
		default:
			c.Errorf("Failed to find user account: %s", err)
		}
	}
	if err := classPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #6
0
func staticTemplate(file string) webapp.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) *webapp.Error {
		t, err := template.ParseFiles("templates/base.html", file)
		if err != nil {
			return webapp.InternalError(fmt.Errorf("Error parsing template %s: %s", file, err))
		}
		if err := t.Execute(w, nil); err != nil {
			return webapp.InternalError(fmt.Errorf("Error rendering template %s: %s", file, err))
		}
		return nil
	}
}
예제 #7
0
func admin(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	staff, err := staff.All(c)
	if err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Staff": staff,
	}
	if err := adminPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #8
0
func addSession(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may add sessions"))
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		fields, err := webapp.ParseRequiredValues(r, "name", "startdate", "enddate")
		if err != nil {
			return missingFields(w)
		}
		start, err := parseLocalDate(fields["startdate"])
		if err != nil {
			return invalidData(w, "Invalid start date; please use mm/dd/yyyy format.")
		}
		end, err := parseLocalDate(fields["enddate"])
		if err != nil {
			return invalidData(w, "Invalid end date; please use mm/dd/yyyy format.")
		}
		session := classes.NewSession(fields["name"], start, end)
		if err := session.Insert(c); err != nil {
			return webapp.InternalError(fmt.Errorf("failed to put session: %s", err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token": token.Encode(),
	}
	if err := addSessionPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #9
0
func doLogin(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	target := continueTarget(r)
	links, err := login.Links(c, login.OpenIDProviders, target)
	if err != nil {
		return webapp.InternalError(fmt.Errorf("failed to create login links: %s", err))
	}
	data := map[string]interface{}{
		"LoginLinks": links,
	}
	if err := loginPage.Execute(w, data); err != nil {
		return webapp.InternalError(fmt.Errorf("Error rendering login page template: %s", err))
	}
	return nil
}
예제 #10
0
func classAndUser(w http.ResponseWriter, r *http.Request) (*account.Account, *classes.Class, *webapp.Error) {
	c := appengine.NewContext(r)
	u := user.Current(c)
	if u == nil {
		return nil, nil, badRequest(w, "Must be logged in.")
	}
	a, err := account.ForUser(c, u)
	if err != nil {
		return nil, nil, badRequest(w, "Must be registered.")
	}
	id, err := strconv.ParseInt(r.FormValue("class"), 10, 64)
	if err != nil {
		return nil, nil, invalidData(w, "Couldn't parse class ID")
	}
	class, err := classes.ClassWithID(c, id)
	switch err {
	case nil:
		break
	case classes.ErrClassNotFound:
		return nil, nil, invalidData(w, "No such class")
	default:
		return nil, nil, webapp.InternalError(fmt.Errorf("failed to look up class %d: %s", id, err))
	}
	return a, class, nil
}
예제 #11
0
func addAnnouncement(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may add announcements"))
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		fields, err := webapp.ParseRequiredValues(r, "text", "expiration")
		if err != nil {
			return missingFields(w)
		}
		expiration, err := parseLocalDate(fields["expiration"])
		if err != nil {
			return invalidData(w, "Invalid date entry; please use mm/dd/yyyy format.")
		}
		c.Infof("expiration: %s", expiration)
		announce := staff.NewAnnouncement(fields["text"], expiration)
		if err := staffAccount.AddAnnouncement(c, announce); err != nil {
			return webapp.InternalError(fmt.Errorf("staff: failed to add announcement: %s", err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token": token.Encode(),
	}
	if err := addAnnouncementPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #12
0
func staffContextHandler(handler webapp.Handler) webapp.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) *webapp.Error {
		c := appengine.NewContext(r)
		account, ok := userContext(r)
		if !ok {
			return webapp.InternalError(fmt.Errorf("staff context requires user context"))
		}
		u := user.Current(c)
		switch staffer, err := maybeOldStaff(c, account, u); err {
		case nil:
			setStaffContext(r, staffer)
			return handler.Serve(w, r)
		case staff.ErrUserIsNotStaff:
			return webapp.UnauthorizedError(fmt.Errorf("%s is not staff", account.Email))
		default:
			return webapp.InternalError(fmt.Errorf("failed to look up staff for %q: %s", account.ID, err))
		}
	}
}
예제 #13
0
func registerForOneDay(w http.ResponseWriter, r *http.Request) *webapp.Error {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method not allowed")
		return nil
	}
	c := appengine.NewContext(r)
	user, class, err := classAndUser(w, r)
	if err != nil {
		return err
	}
	token, ok := checkToken(c, user.ID, r.URL.Path, r.FormValue(auth.TokenFieldName))
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("Invalid auth token"))
	}
	date, dateErr := parseLocalDate(r.FormValue("date"))
	if dateErr != nil {
		return invalidData(w, "Invalid date; please use mm/dd/yyyy format")
	}
	// TODO(rwsims): The date here should really be the end time of the
	// class on the given day.
	student := students.NewDropIn(user, class, date)
	switch err := student.Add(c, time.Now()); err {
	case nil:
		break
	case students.ErrClassIsFull:
		if err := classFullPage.Execute(w, class); err != nil {
			return webapp.InternalError(err)
		}
	default:
		return webapp.InternalError(fmt.Errorf("failed to write student: %s", err))
	}
	token.Delete(c)
	http.Redirect(w, r, "/", http.StatusSeeOther)
	return nil
}
예제 #14
0
func deleteYinYogassage(w http.ResponseWriter, r *http.Request) *webapp.Error {
	fields, err := webapp.ParseRequiredValues(r, "id")
	if err != nil {
		return webapp.InternalError(err)
	}
	id, err := strconv.ParseInt(fields["id"], 10, 64)
	if err != nil {
		return invalidData(w, fmt.Sprintf("Invalid yogassage ID"))
	}
	c := appengine.NewContext(r)
	yin, err := yogassage.WithID(c, id)
	if err != nil {
		return webapp.InternalError(fmt.Errorf("failed to find yogassage %d: %s", id, err))
	}
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may delete yogassage classes"))
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		if err := yin.Delete(c); err != nil {
			return webapp.InternalError(fmt.Errorf("failed to delete yogassage %d: %s", yin.ID, err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token": token.Encode(),
		"Class": yin,
	}
	if err := deleteYinYogassagePage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #15
0
func userContextHandler(handler webapp.Handler) webapp.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) *webapp.Error {
		c := appengine.NewContext(r)
		u := user.Current(c)
		if u == nil {
			webapp.RedirectToLogin(w, r, r.URL.Path)
			return nil
		}
		switch acct, err := maybeOldAccount(c, u); err {
		case nil:
			setUserContext(r, acct)
			return handler.Serve(w, r)
		case account.ErrUserNotFound:
			http.Redirect(w, r, "/login/new", http.StatusSeeOther)
			return nil
		default:
			return webapp.InternalError(fmt.Errorf("failed to look up current user: %s", err))
		}
	}
}
예제 #16
0
func deleteAnnouncement(w http.ResponseWriter, r *http.Request) *webapp.Error {
	fields, err := webapp.ParseRequiredValues(r, "id")
	if err != nil {
		return webapp.InternalError(err)
	}
	id, err := strconv.ParseInt(fields["id"], 10, 64)
	if err != nil {
		return webapp.InternalError(fmt.Errorf("failed to parse %q as announcement ID: %s", fields["id"], err))
	}
	c := appengine.NewContext(r)
	announce, err := staff.AnnouncementWithID(c, id)
	if err != nil {
		return missingFields(w)
	}
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may delete announcements"))
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		if err := announce.Delete(c); err != nil {
			return webapp.InternalError(fmt.Errorf("failed to delete announcement %d: %s", announce.ID, err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token":        token.Encode(),
		"Announcement": announce,
	}
	if err := deleteAnnouncementPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #17
0
func staffPortal(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	teachers := classes.Teachers(c)
	sort.Sort(classes.TeachersByName(teachers))
	announcements := staff.CurrentAnnouncements(c, time.Now())
	sort.Sort(staff.AnnouncementsByExpiration(announcements))
	sessions := classes.Sessions(c, time.Now())
	sort.Sort(classes.SessionsByStartDate(sessions))
	yins := yogassage.Classes(c, time.Now())
	sort.Sort(yogassage.ByDate(yins))
	data := map[string]interface{}{
		"Teachers":            teachers,
		"Announcements":       announcements,
		"Sessions":            sessions,
		"YinYogassageClasses": yins,
	}
	if err := staffPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #18
0
func addTeacher(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	vals, err := webapp.ParseRequiredValues(r, "email")
	if err != nil {
		return webapp.InternalError(err)
	}
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may add teachers"))
	}
	account, err := account.WithEmail(c, vals["email"])
	if err != nil {
		return webapp.InternalError(fmt.Errorf("Couldn't find account for '%s'", vals["email"]))
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		teacher := classes.NewTeacher(account)
		if err := teacher.Put(c); err != nil {
			return webapp.InternalError(fmt.Errorf("Couldn't store teacher for %q: %s", account.Email, err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token": token.Encode(),
		"User":  account,
	}
	if err := addTeacherPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #19
0
func addStaff(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	adminAccount, ok := userContext(r)
	if !ok {
		return webapp.InternalError(fmt.Errorf("user not logged in"))
	}
	account, err := account.WithEmail(c, r.FormValue("email"))
	if err != nil {
		return webapp.InternalError(fmt.Errorf("Couldn't find user for email %s", r.FormValue("email")))
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, adminAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue("xsrf_token"), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("Invalid XSRF token provided"))
		}
		staff := staff.New(account)
		if err := staff.Store(c); err != nil {
			return webapp.InternalError(fmt.Errorf("Couldn't add %s as staff", account.Email))
		}
		http.Redirect(w, r, "/admin", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(adminAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token": token.Encode(),
		"User":  account,
	}
	if err := addStaffPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #20
0
func newAccount(w http.ResponseWriter, r *http.Request) *webapp.Error {
	target := continueTarget(r)
	c := appengine.NewContext(r)
	u := user.Current(c)
	if u == nil {
		webapp.RedirectToLogin(w, r, "/")
		return nil
	}
	if _, err := account.ForUser(c, u); err != account.ErrUserNotFound {
		if err != nil {
			return webapp.InternalError(fmt.Errorf("failed to account for current user: %s", err))
		}
		http.Redirect(w, r, "/", http.StatusFound)
		return nil
	}
	id, err := account.ID(u)
	if err != nil {
		return webapp.InternalError(err)
	}
	if r.Method == "POST" {
		token, err := auth.TokenForRequest(c, id, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("no stored token for request"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid XSRF token"))
		}
		fields, err := webapp.ParseRequiredValues(r, "email", "firstname", "lastname")
		if err != nil {
			// TODO(rwsims): Clean up this error reporting.
			w.WriteHeader(http.StatusBadRequest)
			fmt.Fprintf(w, "Please go back and enter all required data.")
			return nil
		}
		claim := account.NewClaimedEmail(c, id, fields["email"])
		switch err := claim.Claim(c); {
		case err == nil:
			break
		case err == account.ErrEmailAlreadyClaimed:
			// TODO(rwsims): Clean up this error reporting.
			w.WriteHeader(http.StatusBadRequest)
			fmt.Fprintf(w, "That email is already in use; please use a different email")
			return nil
		default:
			return webapp.InternalError(fmt.Errorf("failed to claim email %q: %s", claim.Email, err))
		}
		info := account.Info{
			FirstName: fields["firstname"],
			LastName:  fields["lastname"],
			Email:     fields["email"],
		}
		if phone := r.FormValue("phone"); phone != "" {
			info.Phone = phone
		}
		acct, err := account.New(u, info)
		if err != nil {
			return webapp.InternalError(fmt.Errorf("failed to create user account: %s", err))
		}
		if err := acct.Put(c); err != nil {
			return webapp.InternalError(fmt.Errorf("failed to write new user account: %s", err))
		}
		if err := acct.SendConfirmation(c); err != nil {
			c.Errorf("Failed to send confirmation email to %q: %s", acct.Email, err)
		}
		http.Redirect(w, r, target, http.StatusSeeOther)
		token.Delete(c)
		return nil
	}
	token, err := auth.NewToken(id, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(fmt.Errorf("failed to create auth token: %s", err))
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(fmt.Errorf("failed to store token: %s", err))
	}
	data := map[string]interface{}{
		"Target": target,
		"Token":  token.Encode(),
	}
	if err := newAccountPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #21
0
func registerPaperStudent(w http.ResponseWriter, r *http.Request) *webapp.Error {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method not allowed")
		return nil
	}
	c := appengine.NewContext(r)
	user, class, werr := classAndUser(w, r)
	if werr != nil {
		return werr
	}
	token, ok := checkToken(c, user.ID, r.URL.Path, r.FormValue(auth.TokenFieldName))
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("Invalid auth token"))
	}
	fields, err := webapp.ParseRequiredValues(r, "firstname", "lastname", "email", "type")
	if err != nil {
		return missingFields(w)
	}
	acct, err := account.WithEmail(c, fields["email"])
	switch err {
	case nil:
		// Register with existing account
		break
	case account.ErrUserNotFound:
		// Need to create a paper account for this registration. This account will not be stored.
		info := account.Info{
			FirstName: fields["firstname"],
			LastName:  fields["lastname"],
			Email:     fields["email"],
		}
		if phone := fields["phone"]; phone != "" {
			info.Phone = phone
		}
		acct = account.Paper(info, class.ID)
		break
	default:
		return webapp.InternalError(fmt.Errorf("failed to look up account for %q: %s", fields["email"], err))
	}
	var student *students.Student
	if fields["type"] == "dropin" {
		// TODO(rwsims): The date here should really be the end time of the
		// class on the given day.
		date, err := parseLocalDate(r.FormValue("date"))
		if err != nil {
			return invalidData(w, "Invalid date; please use mm/dd/yyyy format")
		}
		student = students.NewDropIn(acct, class, date)
	} else {
		student = students.New(acct, class)
	}
	switch err := student.Add(c, time.Now()); err {
	case nil:
		break
	case students.ErrClassIsFull:
		if err := classFullPage.Execute(w, class); err != nil {
			return webapp.InternalError(err)
		}
	default:
		return webapp.InternalError(fmt.Errorf("failed to write student: %s", err))
	}
	token.Delete(c)
	http.Redirect(w, r, fmt.Sprintf("/roster?class=%d", class.ID), http.StatusSeeOther)
	return nil
}
예제 #22
0
func throwError(w http.ResponseWriter, r *http.Request) *webapp.Error {
	return webapp.InternalError(fmt.Errorf("this is an intentional error"))
}
예제 #23
0
func editClass(w http.ResponseWriter, r *http.Request) *webapp.Error {
	idString := r.FormValue("class")
	if idString == "" {
		return missingFields(w)
	}
	id, err := strconv.ParseInt(idString, 10, 64)
	if err != nil {
		return invalidData(w, fmt.Sprintf("Invalid class ID"))
	}
	c := appengine.NewContext(r)
	class, err := classes.ClassWithID(c, id)
	switch err {
	case nil:
		break
	case classes.ErrClassNotFound:
		return invalidData(w, "No such class.")
	default:
		return webapp.InternalError(fmt.Errorf("failed to look up class %d: %s", id, err))
	}
	staffAccount, ok := staffContext(r)
	if !ok {
		return webapp.UnauthorizedError(fmt.Errorf("only staff may edit classes"))
	}
	if r.Method == "POST" {
		c.Infof("updating class %d", class.ID)
		token, err := auth.TokenForRequest(c, staffAccount.ID, r.URL.Path)
		if err != nil {
			return webapp.UnauthorizedError(fmt.Errorf("didn't find an auth token"))
		}
		if !token.IsValid(r.FormValue(auth.TokenFieldName), time.Now()) {
			return webapp.UnauthorizedError(fmt.Errorf("invalid auth token"))
		}
		fields, err := webapp.ParseRequiredValues(r, "name", "description", "maxstudents", "dayofweek", "starttime", "length", "dropinonly")
		if err != nil {
			return missingFields(w)
		}
		class.Title = fields["name"]
		class.LongDescription = []byte(fields["description"])
		class.DropInOnly = fields["dropinonly"] == "yes"
		weekday, err := parseWeekday(fields["dayofweek"])
		if err != nil {
			return invalidData(w, "Invalid weekday")
		}
		class.Weekday = weekday
		maxStudents, err := strconv.ParseInt(fields["maxstudents"], 10, 32)
		if err != nil || maxStudents <= 0 {
			return invalidData(w, "Invalid student capacity")
		}
		class.Capacity = int32(maxStudents)
		length, err := parseMinutes(fields["length"])
		if err != nil {
			return invalidData(w, "Invalid length")
		}
		class.Length = length
		start, err := parseLocalTime(fields["starttime"])
		if err != nil {
			return invalidData(w, "Invalid start time; please use HH:MMpm format (e.g., 3:04pm)")
		}
		class.StartTime = start
		if email := r.FormValue("teacher"); email == "" {
			class.Teacher = nil
		} else {
			teacher, err := classes.TeacherWithEmail(c, email)
			if err != nil {
				return invalidData(w, "Invalid teacher selected")
			}
			class.Teacher = teacher.Key(c)
		}
		if err := class.Update(c); err != nil {
			return webapp.InternalError(fmt.Errorf("failed to update class %d: %s", class.ID, err))
		}
		token.Delete(c)
		http.Redirect(w, r, "/staff", http.StatusSeeOther)
		return nil
	}
	token, err := auth.NewToken(staffAccount.ID, r.URL.Path, time.Now())
	if err != nil {
		return webapp.InternalError(err)
	}
	if err := token.Store(c); err != nil {
		return webapp.InternalError(err)
	}
	data := map[string]interface{}{
		"Token":       token.Encode(),
		"Class":       class,
		"Teacher":     class.TeacherEntity(c),
		"Teachers":    classes.Teachers(c),
		"DaysInOrder": daysInOrder,
	}
	if err := editClassPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}
예제 #24
0
func index(w http.ResponseWriter, r *http.Request) *webapp.Error {
	c := appengine.NewContext(r)
	announcements := staff.CurrentAnnouncements(c, time.Now())
	sort.Sort(staff.AnnouncementsByExpiration(announcements))
	sessions := classes.Sessions(c, time.Now())
	schedules := []sessionSchedule{}
	for _, session := range sessions {
		sessionClasses := session.Classes(c)
		if len(sessionClasses) == 0 {
			continue
		}
		sched := sessionSchedule{
			Session:         session,
			ClassesByDay:    classes.GroupedByDay(sessionClasses),
			TeachersByClass: classes.TeachersByClass(c, sessionClasses),
		}
		schedules = append(schedules, sched)
	}
	classesBySession := make(map[int64][]*classes.Class)
	for _, session := range sessions {
		classesBySession[session.ID] = session.Classes(c)
	}
	yins := yogassage.Classes(c, dateOnly(time.Now()))
	sort.Sort(yogassage.ByDate(yins))
	data := map[string]interface{}{
		"Announcements": announcements,
		"Schedules":     schedules,
		"DaysInOrder":   daysInOrder,
		"YinYogassage":  yins,
	}
	if u := user.Current(c); u != nil {
		acct, err := maybeOldAccount(c, u)
		switch err {
		case nil:
			break
		case account.ErrUserNotFound:
			http.Redirect(w, r, "/login/new", http.StatusSeeOther)
			return nil
		default:
			return webapp.InternalError(fmt.Errorf("failed to find user: %s", err))
		}
		data["LoggedIn"] = true
		data["User"] = acct
		if url, err := user.LogoutURL(c, "/"); err != nil {
			return webapp.InternalError(fmt.Errorf("Error creating logout url: %s", err))
		} else {
			data["LogoutURL"] = url
		}
		switch staffer, err := maybeOldStaff(c, acct, u); err {
		case nil:
			data["Staff"] = staffer
		case staff.ErrUserIsNotStaff:
			break
		default:
			return webapp.InternalError(err)
		}
		data["Admin"] = user.IsAdmin(c)
		regs := registrationsForUser(c, acct.ID)
		if len(regs) == 0 {
			regs = registrationsForUser(c, u.ID)
		}
		data["Registrations"] = regs
	}
	if err := indexPage.Execute(w, data); err != nil {
		return webapp.InternalError(err)
	}
	return nil
}