Function bodies 190 total
db.IsUserOnAnyTeamInProject function · go · L211-L222 (12 LOC)internal/db/helpers.go
func IsUserOnAnyTeamInProject(app *pocketbase.PocketBase, projectId, userId string) (bool, error) {
_, err := app.FindFirstRecordByFilter("team_members",
"user = {:user} && team.project = {:project} && removed_at = ''",
map[string]any{"user": userId, "project": projectId})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return false, nil
}
return false, err
}
return true, nil
}db.GetReviewsByProject function · go · L227-L234 (8 LOC)internal/db/helpers.go
func GetReviewsByProject(app *pocketbase.PocketBase, projectId string) ([]*core.Record, error) {
return app.FindRecordsByFilter("reviews",
"project = {:project}",
"",
0,
0,
map[string]any{"project": projectId})
}db.GetRatingsByReview function · go · L251-L258 (8 LOC)internal/db/helpers.go
func GetRatingsByReview(app *pocketbase.PocketBase, reviewId string) ([]*core.Record, error) {
return app.FindRecordsByFilter("ratings",
"review = {:review}",
"",
0,
0,
map[string]any{"review": reviewId})
}db.GetRatingsByRatee function · go · L261-L268 (8 LOC)internal/db/helpers.go
func GetRatingsByRatee(app *pocketbase.PocketBase, rateeId string) ([]*core.Record, error) {
return app.FindRecordsByFilter("ratings",
"ratee = {:ratee}",
"",
0,
0,
map[string]any{"ratee": rateeId})
}db.GetTeammatesForUserInProject function · go · L278-L306 (29 LOC)internal/db/helpers.go
func GetTeammatesForUserInProject(app *pocketbase.PocketBase, userId, projectId string) ([]*core.Record, error) {
// First find the user's ACTIVE team for this project
teamMember, err := app.FindFirstRecordByFilter("team_members",
"user = {:user} && team.project = {:project} && removed_at = ''",
map[string]any{"user": userId, "project": projectId})
if err != nil {
return nil, err
}
teamId := teamMember.GetString("team")
// Get all ACTIVE members of that team (including the user)
members, err := GetActiveTeamMembersByTeam(app, teamId)
if err != nil {
return nil, err
}
// Expand to get user records
var teammates []*core.Record
for _, member := range members {
userRecord, err := app.FindRecordById("users", member.GetString("user"))
if err != nil {
continue
}
teammates = append(teammates, userRecord)
}
return teammates, nil
}db.ValidateNetId function · go · L322-L339 (18 LOC)internal/db/helpers.go
func ValidateNetId(netid string) (string, error) {
normalized := strings.ToLower(strings.TrimSpace(netid))
if len(normalized) < 2 {
return "", fmt.Errorf("netid too short: %q", netid)
}
if len(normalized) > 16 {
return "", fmt.Errorf("netid too long: %q", netid)
}
if strings.Contains(normalized, "@") {
return "", fmt.Errorf("netid cannot contain @: %q", netid)
}
if strings.ContainsAny(normalized, " \t\n\r") {
return "", fmt.Errorf("netid cannot contain whitespace: %q", netid)
}
return normalized, nil
}db.GetOrCreateUserByNetId function · go · L345-L387 (43 LOC)internal/db/helpers.go
func GetOrCreateUserByNetId(app *pocketbase.PocketBase, netid string) (*core.Record, bool, error) {
normalized, err := ValidateNetId(netid)
if err != nil {
return nil, false, err
}
// Try to find existing user by netid
record, err := app.FindFirstRecordByFilter("users", "netid = {:netid}", map[string]any{"netid": normalized})
if err == nil {
return record, false, nil
}
// Only create stub on "not found" error, not on transient DB errors
if !errors.Is(err, sql.ErrNoRows) {
return nil, false, fmt.Errorf("failed to lookup user: %w", err)
}
// User doesn't exist, create stub
collection, err := app.FindCollectionByNameOrId("users")
if err != nil {
return nil, false, fmt.Errorf("failed to find users collection: %w", err)
}
record = core.NewRecord(collection)
record.Set("netid", normalized)
record.Set("name", normalized) // Placeholder, will be updated on CAS login
record.Set("email", normalized+"@yale.edu")
record.Set("is_teacher", false)
// Generate random pMethodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
db.generateRandomPassword function · go · L390-L396 (7 LOC)internal/db/helpers.go
func generateRandomPassword(length int) (string, error) {
bytes := make([]byte, length)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}db.GetTeamMemberCount function · go · L399-L405 (7 LOC)internal/db/helpers.go
func GetTeamMemberCount(app *pocketbase.PocketBase, teamId string) (int, error) {
members, err := GetActiveTeamMembersByTeam(app, teamId)
if err != nil {
return 0, err
}
return len(members), nil
}db.GetActiveTeamMembersByTeam function · go · L410-L417 (8 LOC)internal/db/helpers.go
func GetActiveTeamMembersByTeam(app *pocketbase.PocketBase, teamId string) ([]*core.Record, error) {
return app.FindRecordsByFilter("team_members",
"team = {:team} && removed_at = ''",
"",
0,
0,
map[string]any{"team": teamId})
}db.GetActiveTeamMembersByProject function · go · L420-L427 (8 LOC)internal/db/helpers.go
func GetActiveTeamMembersByProject(app *pocketbase.PocketBase, projectId string) ([]*core.Record, error) {
return app.FindRecordsByFilter("team_members",
"team.project = {:project} && removed_at = ''",
"",
0,
0,
map[string]any{"project": projectId})
}db.IsUserActiveOnAnyTeamInProject function · go · L437-L448 (12 LOC)internal/db/helpers.go
func IsUserActiveOnAnyTeamInProject(app *pocketbase.PocketBase, projectId, userId string) (bool, error) {
_, err := app.FindFirstRecordByFilter("team_members",
"user = {:user} && team.project = {:project} && removed_at = ''",
map[string]any{"user": userId, "project": projectId})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return false, nil
}
return false, err
}
return true, nil
}db.HasProjectReviews function · go · L453-L464 (12 LOC)internal/db/helpers.go
func HasProjectReviews(app *pocketbase.PocketBase, projectId string) (bool, error) {
reviews, err := app.FindRecordsByFilter("reviews",
"project = {:project}",
"",
1, // Only need to find one
0,
map[string]any{"project": projectId})
if err != nil {
return false, err
}
return len(reviews) > 0, nil
}db.GetProjectReviewCount function · go · L467-L473 (7 LOC)internal/db/helpers.go
func GetProjectReviewCount(app *pocketbase.PocketBase, projectId string) (int, error) {
reviews, err := GetReviewsByProject(app, projectId)
if err != nil {
return 0, err
}
return len(reviews), nil
}db.GetReviewImpactForUser function · go · L486-L528 (43 LOC)internal/db/helpers.go
func GetReviewImpactForUser(app *pocketbase.PocketBase, userId, projectId string) (*ReviewImpact, error) {
// Get user info
user, err := app.FindRecordById("users", userId)
if err != nil {
return nil, fmt.Errorf("failed to find user: %w", err)
}
impact := &ReviewImpact{
UserID: userId,
UserName: user.GetString("name"),
UserNetID: user.GetString("netid"),
}
// Check if user has submitted a review
review, err := GetReviewByProjectAndReviewer(app, projectId, userId)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, fmt.Errorf("failed to check review: %w", err)
}
impact.HasSubmittedReview = review != nil
// Count ratings given (if they submitted a review)
if review != nil {
ratings, err := GetRatingsByReview(app, review.Id)
if err != nil {
return nil, fmt.Errorf("failed to count ratings given: %w", err)
}
impact.RatingsGivenCount = len(ratings)
}
// Count ratings received (from all reviews in this project where ratee = user)
ratingsRCitation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
db.GetReviewImpactForUsers function · go · L531-L541 (11 LOC)internal/db/helpers.go
func GetReviewImpactForUsers(app *pocketbase.PocketBase, userIds []string, projectId string) (map[string]*ReviewImpact, error) {
impacts := make(map[string]*ReviewImpact)
for _, userId := range userIds {
impact, err := GetReviewImpactForUser(app, userId, projectId)
if err != nil {
return nil, err
}
impacts[userId] = impact
}
return impacts, nil
}db.SoftDeleteTeamMember function · go · L544-L554 (11 LOC)internal/db/helpers.go
func SoftDeleteTeamMember(app *pocketbase.PocketBase, teamMemberId, removedById string) error {
record, err := app.FindRecordById("team_members", teamMemberId)
if err != nil {
return fmt.Errorf("failed to find team member: %w", err)
}
record.Set("removed_at", time.Now().UTC())
record.Set("removed_by", removedById)
return app.Save(record)
}db.GetClassStaffMembers function · go · L559-L581 (23 LOC)internal/db/helpers.go
func GetClassStaffMembers(app *pocketbase.PocketBase, classId string) ([]*core.Record, error) {
class, err := app.FindRecordById("classes", classId)
if err != nil {
return nil, fmt.Errorf("failed to find class: %w", err)
}
staffIds := class.GetStringSlice("staff")
if len(staffIds) == 0 {
return []*core.Record{}, nil
}
var staffMembers []*core.Record
for _, staffId := range staffIds {
user, err := app.FindRecordById("users", staffId)
if err != nil {
// Skip users that don't exist (shouldn't happen, but be defensive)
continue
}
staffMembers = append(staffMembers, user)
}
return staffMembers, nil
}db.AddClassStaff function · go · L584-L604 (21 LOC)internal/db/helpers.go
func AddClassStaff(app *pocketbase.PocketBase, classId, userId string) error {
class, err := app.FindRecordById("classes", classId)
if err != nil {
return fmt.Errorf("failed to find class: %w", err)
}
currentStaff := class.GetStringSlice("staff")
// Check if user is already staff
for _, id := range currentStaff {
if id == userId {
return nil // Already staff, nothing to do
}
}
// Add user to staff list
currentStaff = append(currentStaff, userId)
class.Set("staff", currentStaff)
return app.Save(class)
}db.RemoveClassStaff function · go · L607-L624 (18 LOC)internal/db/helpers.go
func RemoveClassStaff(app *pocketbase.PocketBase, classId, userId string) error {
class, err := app.FindRecordById("classes", classId)
if err != nil {
return fmt.Errorf("failed to find class: %w", err)
}
currentStaff := class.GetStringSlice("staff")
newStaff := make([]string, 0, len(currentStaff))
for _, id := range currentStaff {
if id != userId {
newStaff = append(newStaff, id)
}
}
class.Set("staff", newStaff)
return app.Save(class)
}db.GetPendingReviews function · go · L81-L89 (9 LOC)internal/db/queries.go
func GetPendingReviews(app *pocketbase.PocketBase, userId string) ([]PendingReview, error) {
var results []PendingReview
err := app.DB().
NewQuery(pendingReviewsSQL).
Bind(dbx.Params{"userId": userId}).
All(&results)
return results, err
}db.GetProjectResults function · go · L92-L100 (9 LOC)internal/db/queries.go
func GetProjectResults(app *pocketbase.PocketBase, projectId string) ([]ProjectResult, error) {
var results []ProjectResult
err := app.DB().
NewQuery(projectResultsSQL).
Bind(dbx.Params{"projectId": projectId}).
All(&results)
return results, err
}db.GetReviewDetails function · go · L104-L112 (9 LOC)internal/db/queries.go
func GetReviewDetails(app *pocketbase.PocketBase, rateeId, projectId string) ([]ReviewDetail, error) {
var results []ReviewDetail
err := app.DB().
NewQuery(reviewDetailSQL).
Bind(dbx.Params{"rateeId": rateeId, "projectId": projectId}).
All(&results)
return results, err
}About: code-quality intelligence by Repobility · https://repobility.com
db.GetStudentSubmissions function · go · L115-L123 (9 LOC)internal/db/queries.go
func GetStudentSubmissions(app *pocketbase.PocketBase, userId string) ([]StudentSubmission, error) {
var results []StudentSubmission
err := app.DB().
NewQuery(studentSubmissionsSQL).
Bind(dbx.Params{"userId": userId}).
All(&results)
return results, err
}db.GetProjectRoster function · go · L136-L144 (9 LOC)internal/db/queries.go
func GetProjectRoster(app *pocketbase.PocketBase, projectId string) ([]RosterEntry, error) {
var results []RosterEntry
err := app.DB().
NewQuery(projectRosterSQL).
Bind(dbx.Params{"projectId": projectId}).
All(&results)
return results, err
}db.GetProjectProgress function · go · L156-L167 (12 LOC)internal/db/queries.go
func GetProjectProgress(app *pocketbase.PocketBase, projectId string) (*ProjectProgress, error) {
var result ProjectProgress
err := app.DB().
NewQuery(projectProgressSQL).
Bind(dbx.Params{"projectId": projectId}).
One(&result)
if err != nil {
return nil, err
}
return &result, nil
}db.GetProjectsProgressByClass function · go · L171-L188 (18 LOC)internal/db/queries.go
func GetProjectsProgressByClass(app *pocketbase.PocketBase, classId string) (map[string]ProjectProgress, error) {
var results []ProjectProgress
err := app.DB().
NewQuery(projectsProgressSQL).
Bind(dbx.Params{"classId": classId}).
All(&results)
if err != nil {
return nil, err
}
// Convert to map for O(1) lookup by project ID
progressMap := make(map[string]ProjectProgress)
for _, p := range results {
progressMap[p.ProjectId] = p
}
return progressMap, nil
}handlers.ClassListHandler function · go · L15-L52 (38 LOC)internal/handlers/classes.go
func ClassListHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
// Get all teacher's classes (including archived)
allClasses, err := db.GetClassesByTeacher(app, user.Id, true)
if err != nil {
log.Printf("Failed to get classes: %v", err)
http.Error(w, "Failed to load classes", http.StatusInternalServerError)
return
}
// Split into active and archived classes
var activeClasses, archivedClasses []*core.Record
for _, class := range allClasses {
if class.GetBool("archived") {
archivedClasses = append(archivedClasses, class)
} else {
activeClasses = append(activeClasses, class)
}
}
// Build breadcrumbs
crumbs := []components.BreadcrumbItem{
components.HomeCrumb(),
components.CurrentPageCrumb("Classes"),
}
// Render page
page := components.Page("My Classes",
components.Container(crumbs, user,
components.ClassList(activeClasses, archivedhandlers.ClassCreateHandler function · go · L55-L112 (58 LOC)internal/handlers/classes.go
func ClassCreateHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
if r.Method == "GET" {
// Build breadcrumbs
crumbs := []components.BreadcrumbItem{
components.HomeCrumb(),
components.ClassesCrumb(),
components.CurrentPageCrumb("Create Class"),
}
page := components.Page("Create Class",
components.Container(crumbs, user,
components.ClassForm(nil),
),
)
components.RenderComponent(w, page)
return
}
// POST: Create class
if err := r.ParseForm(); err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
// Validate required fields
courseID := r.FormValue("course_id")
instance := r.FormValue("instance")
if courseID == "" || instance == "" {
http.Error(w, "course_id and instance are required", http.StatusBadRequest)
return
}
collection, err := app.FindCollectionByNameOrId("classes")
if err != nhandlers.ClassDetailHandler function · go · L115-L167 (53 LOC)internal/handlers/classes.go
func ClassDetailHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
classId := r.PathValue("id")
// Get class (verify teacher owns it)
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Class not found or unauthorized: %v", err)
http.Error(w, "Class not found", http.StatusNotFound)
return
}
// Get projects for this class
projects, err := db.GetProjectsByClass(app, classId)
if err != nil {
log.Printf("Failed to get projects: %v", err)
projects = []*core.Record{}
}
// Get progress stats for all projects in this class
progressMap, err := db.GetProjectsProgressByClass(app, classId)
if err != nil {
log.Printf("Failed to get project progress: %v", err)
progressMap = make(map[string]db.ProjectProgress)
}
// Get staff members for this class
staffMembers, err := db.GetClassStaffMembers(app, classId)
if err != nilhandlers.ClassArchiveHandler function · go · L171-L203 (33 LOC)internal/handlers/classes.go
func ClassArchiveHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
classId := r.PathValue("id")
// Get class (verify user has access - teacher or staff)
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Class not found or unauthorized: %v", err)
http.Error(w, "Class not found", http.StatusNotFound)
return
}
// Only the class owner can archive/unarchive - staff cannot
if !db.IsClassOwner(class, user.Id) {
log.Printf("Staff member %s attempted to archive class %s", user.Id, classId)
http.Error(w, "Only the class owner can archive or unarchive a class", http.StatusForbidden)
return
}
// Toggle archived status
class.Set("archived", !class.GetBool("archived"))
if err := app.Save(class); err != nil {
log.Printf("Failed to update class: %v", err)
http.Error(w, "Failed to update class", http.StatusInternalServerErroRepobility — same analyzer, your code, free for public repos · /scan/
handlers.StaffAddHandler function · go · L207-L275 (69 LOC)internal/handlers/classes.go
func StaffAddHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
classId := r.PathValue("id")
// Get class (verify user has access)
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Class not found or unauthorized: %v", err)
http.Error(w, "Class not found", http.StatusNotFound)
return
}
// Only the class owner can manage staff
if !db.IsClassOwner(class, user.Id) {
log.Printf("Non-owner %s attempted to add staff to class %s", user.Id, classId)
http.Error(w, "Only the class owner can manage staff", http.StatusForbidden)
return
}
// Parse form
if err := r.ParseForm(); err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
netid := r.FormValue("netid")
if netid == "" {
http.Error(w, "NetID is required", http.StatusBadRequest)
return
}
// Validate and normalize netid
norhandlers.StaffRemoveHandler function · go · L279-L311 (33 LOC)internal/handlers/classes.go
func StaffRemoveHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
classId := r.PathValue("id")
staffUserId := r.PathValue("userId")
// Get class (verify user has access)
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Class not found or unauthorized: %v", err)
http.Error(w, "Class not found", http.StatusNotFound)
return
}
// Only the class owner can manage staff
if !db.IsClassOwner(class, user.Id) {
log.Printf("Non-owner %s attempted to remove staff from class %s", user.Id, classId)
http.Error(w, "Only the class owner can manage staff", http.StatusForbidden)
return
}
// Remove user from class staff
// Note: We don't unset is_teacher - the user might be staff elsewhere
if err := db.RemoveClassStaff(app, classId, staffUserId); err != nil {
log.Printf("Failed to remove staff: %v", err)
http.Error(w, "Failed handlers.HomeHandler function · go · L17-L49 (33 LOC)internal/handlers/home.go
func HomeHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Manually check authentication since this is a public route
// Get token from cookie or header
var token string
cookie, err := r.Cookie("pb_auth")
if err == nil && cookie.Value != "" {
token = cookie.Value
}
// Try to get user from token
var user *core.Record
if token != "" {
user, _ = app.FindAuthRecordByToken(token, "auth")
}
if user == nil {
// Not authenticated, show landing page
page := components.Page("Yale Peer Review",
LandingPage(),
)
components.RenderComponent(w, page)
return
}
// Authenticated - redirect based on role
if user.GetBool("is_teacher") {
http.Redirect(w, r, "/classes", http.StatusSeeOther)
} else {
http.Redirect(w, r, "/reviews", http.StatusSeeOther)
}
}
}handlers.LandingPage function · go · L52-L59 (8 LOC)internal/handlers/home.go
func LandingPage() g.Node {
return Main(Class("container"),
H1(g.Text("Yale Peer Review System")),
P(g.Text("A web application for managing peer reviews in Yale courses.")),
P(g.Text("Please sign in with your Yale NetID to continue.")),
A(Href("/auth/cas/login"), Role("button"), g.Text("Sign In with Yale CAS")),
)
}handlers.checkClassNotArchived function · go · L25-L31 (7 LOC)internal/handlers/projects.go
func checkClassNotArchived(w http.ResponseWriter, class *core.Record) bool {
if class.GetBool("archived") {
http.Error(w, classArchivedError, http.StatusForbidden)
return true
}
return false
}handlers.ProjectCreateHandler function · go · L34-L103 (70 LOC)internal/handlers/projects.go
func ProjectCreateHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
classId := r.PathValue("classId")
// Verify teacher owns the class
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Class not found or unauthorized: %v", err)
http.Error(w, "Class not found", http.StatusNotFound)
return
}
// Check if class is archived (for POST requests)
if r.Method == "POST" && checkClassNotArchived(w, class) {
return
}
if r.Method == "GET" {
// Build breadcrumbs
crumbs := []components.BreadcrumbItem{
components.HomeCrumb(),
components.ClassesCrumb(),
components.ClassCrumb(class),
components.CurrentPageCrumb("Create Project"),
}
page := components.Page("Create Project",
components.Container(crumbs, user,
components.ProjectForm(class, nil),
),
)
components.RenderComponent(w, page)
return
handlers.ProjectDetailHandler function · go · L106-L158 (53 LOC)internal/handlers/projects.go
func ProjectDetailHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Get class and verify teacher owns it
classId := project.GetString("class")
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Get teams for this project with members
teams, err := db.GetTeamsWithMembersByProject(app, projectId)
if err != nil {
log.Printf("Failed to get teams: %v", err)
teams = []db.TeamWithMembers{}
}
// Get submission progress stats
progress, err := db.GetProjectProgress(app, projectId)
if erhandlers.ProjectEditHandler function · go · L161-L232 (72 LOC)internal/handlers/projects.go
func ProjectEditHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Verify teacher owns the class
classId := project.GetString("class")
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Check if class is archived (for POST requests)
if r.Method == "POST" && checkClassNotArchived(w, class) {
return
}
if r.Method == "GET" {
// Build breadcrumbs
crumbs := []components.BreadcrumbItem{
components.HomeCrumb(),
components.ClassesCrumb(),
components.ClassCrumb(class),
compMethodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
handlers.ProjectToggleHandler function · go · L235-L274 (40 LOC)internal/handlers/projects.go
func ProjectToggleHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Verify teacher owns the class
classId := project.GetString("class")
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Check if class is archived
if checkClassNotArchived(w, class) {
return
}
// Toggle is_open status
project.Set("is_open", !project.GetBool("is_open"))
if err := app.Save(project); err != nil {
log.Printf("Failed to update project: %v", err)
http.Error(w, "Failed to update project", http.Statuhandlers.TeamUploadHandler function · go · L289-L463 (175 LOC)internal/handlers/projects.go
func TeamUploadHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Verify teacher owns the class
classId := project.GetString("class")
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Check if class is archived
if checkClassNotArchived(w, class) {
return
}
// Parse CSV file
file, _, err := r.FormFile("teams_csv")
if err != nil {
log.Printf("Failed to read file: %v", err)
http.Error(w, "Failed to read file", http.StatusBadRequest)
return
}
defer file.Close()
reader :handlers.ProjectProgressStreamHandler function · go · L468-L508 (41 LOC)internal/handlers/projects.go
func ProjectProgressStreamHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Verify teacher owns the project's class (defense in depth)
project, err := db.GetProjectById(app, projectId)
if err != nil {
http.Error(w, "Project not found", http.StatusNotFound)
return
}
classId := project.GetString("class")
if _, err := db.GetClassByIdAndTeacher(app, classId, user.Id); err != nil {
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
sse := datastar.NewSSE(w, r)
// Send initial fragment immediately
var lastStudents, lastTeams int
if err := sendProgressFragment(app, sse, projectId, &lastStudents, &lastTeams); err != nil {
return
}
// Poll every 5 seconds; only send if data changed
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if err := sendProgressFraghandlers.sendProgressFragment function · go · L510-L528 (19 LOC)internal/handlers/projects.go
func sendProgressFragment(app *pocketbase.PocketBase, sse *datastar.ServerSentEventGenerator, projectId string, lastStudents, lastTeams *int) error {
progress, err := db.GetProjectProgress(app, projectId)
if err != nil {
progress = &db.ProjectProgress{}
}
// Skip if nothing changed
if progress.StudentsSubmitted == *lastStudents && progress.TeamsSubmitted == *lastTeams {
return nil
}
*lastStudents = progress.StudentsSubmitted
*lastTeams = progress.TeamsSubmitted
var buf bytes.Buffer
if err := components.ProjectProgressStats(projectId, progress).Render(&buf); err != nil {
return err
}
return sse.MergeFragments(buf.String())
}handlers.sanitizeCSVField function · go · L20-L26 (7 LOC)internal/handlers/results.go
func sanitizeCSVField(s string) string {
trimmed := strings.TrimLeft(s, " \t\r\n")
if len(trimmed) > 0 && (trimmed[0] == '=' || trimmed[0] == '+' || trimmed[0] == '-' || trimmed[0] == '@') {
return "'" + s
}
return s
}handlers.ResultsViewHandler function · go · L29-L76 (48 LOC)internal/handlers/results.go
func ResultsViewHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Get class and verify teacher owns it
classId := project.GetString("class")
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Get aggregated results
results, err := db.GetProjectResults(app, projectId)
if err != nil {
log.Printf("Failed to get results: %v", err)
http.Error(w, "Failed to get results", http.StatusInternalServerError)
return
}
// Build breadcrumbs
crumbs := []components.BreadcrumbItem{
componenhandlers.ResultDetailHandler function · go · L79-L164 (86 LOC)internal/handlers/results.go
func ResultDetailHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("projectId")
userId := r.PathValue("userId")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Get class and verify teacher owns it
classId := project.GetString("class")
class, err := db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Get student record
student, err := app.FindRecordById("users", userId)
if err != nil {
log.Printf("Student not found: %v", err)
http.Error(w, "Student not found", http.StatusNotFound)
return
}
// Get aggregated result for this student
results, erhandlers.StudentOwnResultsHandler function · go · L168-L275 (108 LOC)internal/handlers/results.go
func StudentOwnResultsHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Verify student is in this project by checking team membership
teamMembers, err := db.GetTeamMembersByProject(app, projectId)
if err != nil {
log.Printf("Failed to get team members: %v", err)
http.Error(w, "Failed to get team members", http.StatusInternalServerError)
return
}
inProject := false
for _, tm := range teamMembers {
if tm.GetString("user") == user.Id {
inProject = true
break
}
}
if !inProject {
log.Printf("Student not in project")
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Get review details for this studCitation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
handlers.ResultsExportHandler function · go · L278-L349 (72 LOC)internal/handlers/results.go
func ResultsExportHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
projectId := r.PathValue("id")
// Get project
project, err := db.GetProjectById(app, projectId)
if err != nil {
log.Printf("Project not found: %v", err)
http.Error(w, "Project not found", http.StatusNotFound)
return
}
// Verify teacher owns the class
classId := project.GetString("class")
_, err = db.GetClassByIdAndTeacher(app, classId, user.Id)
if err != nil {
log.Printf("Unauthorized access to project: %v", err)
http.Error(w, "Unauthorized", http.StatusForbidden)
return
}
// Get aggregated results
results, err := db.GetProjectResults(app, projectId)
if err != nil {
log.Printf("Failed to get results: %v", err)
http.Error(w, "Failed to get results", http.StatusInternalServerError)
return
}
// Set headers for CSV download
filename := fmt.Sprintf("results-%s.csv", projecthandlers.ReviewsListHandler function · go · L22-L80 (59 LOC)internal/handlers/reviews.go
func ReviewsListHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
if user == nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Get pending reviews (not yet submitted)
pending, err := db.GetPendingReviews(app, user.Id)
if err != nil {
http.Error(w, "Failed to load reviews", http.StatusInternalServerError)
return
}
// Get all submitted reviews
submissions, err := db.GetStudentSubmissions(app, user.Id)
if err != nil {
http.Error(w, "Failed to load submissions", http.StatusInternalServerError)
return
}
// Split submissions into editable vs completed
var editable, completed []db.StudentSubmission
now := time.Now()
for _, sub := range submissions {
deadline := timezone.ParseDatabaseTime(sub.Deadline)
if sub.IsOpen && now.Before(deadline) {
editable = append(editable, sub)
} else {
completed = append(completed, sub)
handlers.ReviewSubmitHandler function · go · L83-L101 (19 LOC)internal/handlers/reviews.go
func ReviewSubmitHandler(app *pocketbase.PocketBase) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := auth.GetAuthUser(r)
if user == nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
projectId := r.PathValue("projectId")
if r.Method == "GET" {
handleReviewFormGet(app, w, r, user, projectId)
return
}
// POST: Save review
handleReviewFormPost(app, w, r, user, projectId)
}
}