Skip to content

Commit 5e55964

Browse files
salmonumbrellaclaude
authored andcommitted
fix(classroom): add tests, nil guards, and topic filter
- Add comprehensive unit tests for classroom helper functions (date/time parsing, error wrapping, profile helpers) - Add profileEmail() helper for nil-safe email extraction - Fix nil pointer guards for Profile access (12 locations in courses, rosters, and guardians) - Add --topic filter for coursework and materials list commands - Update docs/spec.md with new filter options Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 9b96009 commit 5e55964

8 files changed

Lines changed: 667 additions & 20 deletions

docs/spec.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,13 @@ Flag aliases:
185185
- `gog classroom teachers add <courseId> <userId>`
186186
- `gog classroom teachers remove <courseId> <userId>`
187187
- `gog classroom roster <courseId> [--students] [--teachers]`
188-
- `gog classroom coursework <courseId> [--state ...] [--max N] [--page TOKEN]`
188+
- `gog classroom coursework <courseId> [--state ...] [--topic TOPIC_ID] [--max N] [--page TOKEN]`
189189
- `gog classroom coursework get <courseId> <courseworkId>`
190190
- `gog classroom coursework create <courseId> --title TITLE [--type ASSIGNMENT|...]`
191191
- `gog classroom coursework update <courseId> <courseworkId> [--title ...]`
192192
- `gog classroom coursework delete <courseId> <courseworkId>`
193193
- `gog classroom coursework assignees <courseId> <courseworkId> [--mode ...] [--add-student ...]`
194-
- `gog classroom materials <courseId> [--state ...] [--max N] [--page TOKEN]`
194+
- `gog classroom materials <courseId> [--state ...] [--topic TOPIC_ID] [--max N] [--page TOKEN]`
195195
- `gog classroom materials get <courseId> <materialId>`
196196
- `gog classroom materials create <courseId> --title TITLE`
197197
- `gog classroom materials update <courseId> <materialId> [--title ...]`

internal/cmd/classroom_courses.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func (c *ClassroomCoursesJoinCmd) Run(ctx context.Context, flags *RootFlags) err
423423
return outfmt.WriteJSON(os.Stdout, map[string]any{"student": created})
424424
}
425425
u.Out().Printf("user_id\t%s", created.UserId)
426-
u.Out().Printf("email\t%s", created.Profile.EmailAddress)
426+
u.Out().Printf("email\t%s", profileEmail(created.Profile))
427427
u.Out().Printf("name\t%s", profileName(created.Profile))
428428
return nil
429429
case "teacher":
@@ -436,7 +436,7 @@ func (c *ClassroomCoursesJoinCmd) Run(ctx context.Context, flags *RootFlags) err
436436
return outfmt.WriteJSON(os.Stdout, map[string]any{"teacher": created})
437437
}
438438
u.Out().Printf("user_id\t%s", created.UserId)
439-
u.Out().Printf("email\t%s", created.Profile.EmailAddress)
439+
u.Out().Printf("email\t%s", profileEmail(created.Profile))
440440
u.Out().Printf("name\t%s", profileName(created.Profile))
441441
return nil
442442
default:

internal/cmd/classroom_coursework.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type ClassroomCourseworkCmd struct {
2424
type ClassroomCourseworkListCmd struct {
2525
CourseID string `arg:"" name:"courseId" help:"Course ID or alias"`
2626
States string `name:"state" help:"Coursework states filter (comma-separated: DRAFT,PUBLISHED,DELETED)"`
27+
Topic string `name:"topic" help:"Filter by topic ID"`
2728
OrderBy string `name:"order-by" help:"Order by (e.g., updateTime desc, dueDate desc)"`
2829
Max int64 `name:"max" aliases:"limit" help:"Max results" default:"100"`
2930
Page string `name:"page" help:"Page token"`
@@ -62,22 +63,35 @@ func (c *ClassroomCourseworkListCmd) Run(ctx context.Context, flags *RootFlags)
6263
return wrapClassroomError(err)
6364
}
6465

66+
// Client-side filter by topic (API doesn't support server-side topic filter)
67+
topicFilter := strings.TrimSpace(c.Topic)
68+
coursework := resp.CourseWork
69+
if topicFilter != "" {
70+
filtered := make([]*classroom.CourseWork, 0, len(coursework))
71+
for _, work := range coursework {
72+
if work != nil && work.TopicId == topicFilter {
73+
filtered = append(filtered, work)
74+
}
75+
}
76+
coursework = filtered
77+
}
78+
6579
if outfmt.IsJSON(ctx) {
6680
return outfmt.WriteJSON(os.Stdout, map[string]any{
67-
"coursework": resp.CourseWork,
81+
"coursework": coursework,
6882
"nextPageToken": resp.NextPageToken,
6983
})
7084
}
7185

72-
if len(resp.CourseWork) == 0 {
86+
if len(coursework) == 0 {
7387
u.Err().Println("No coursework")
7488
return nil
7589
}
7690

7791
w, flush := tableWriter(ctx)
7892
defer flush()
7993
fmt.Fprintln(w, "ID\tTITLE\tSTATE\tDUE\tTYPE\tMAX_POINTS")
80-
for _, work := range resp.CourseWork {
94+
for _, work := range coursework {
8195
if work == nil {
8296
continue
8397
}

internal/cmd/classroom_guardians.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (c *ClassroomGuardiansListCmd) Run(ctx context.Context, flags *RootFlags) e
7272
}
7373
fmt.Fprintf(w, "%s\t%s\t%s\n",
7474
sanitizeTab(guardian.GuardianId),
75-
sanitizeTab(guardian.GuardianProfile.EmailAddress),
75+
sanitizeTab(profileEmail(guardian.GuardianProfile)),
7676
sanitizeTab(profileName(guardian.GuardianProfile)),
7777
)
7878
}
@@ -116,7 +116,7 @@ func (c *ClassroomGuardiansGetCmd) Run(ctx context.Context, flags *RootFlags) er
116116

117117
u.Out().Printf("id\t%s", guardian.GuardianId)
118118
u.Out().Printf("student_id\t%s", guardian.StudentId)
119-
u.Out().Printf("email\t%s", guardian.GuardianProfile.EmailAddress)
119+
u.Out().Printf("email\t%s", profileEmail(guardian.GuardianProfile))
120120
u.Out().Printf("name\t%s", profileName(guardian.GuardianProfile))
121121
return nil
122122
}

internal/cmd/classroom_helpers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ func profileName(profile *classroom.UserProfile) string {
140140
return strings.TrimSpace(strings.TrimSpace(profile.Name.GivenName + " " + profile.Name.FamilyName))
141141
}
142142

143+
func profileEmail(profile *classroom.UserProfile) string {
144+
if profile == nil {
145+
return ""
146+
}
147+
return profile.EmailAddress
148+
}
149+
143150
func formatFloatValue(v float64) string {
144151
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", v), "0"), ".")
145152
}

0 commit comments

Comments
 (0)