Documentation
¶
Index ¶
- Constants
- func AdminAuditLogFacets(gdb *gorm.DB) (actions, resources []string, err error)
- func AdminForgejoRequestFacets(gdb *gorm.DB) (sources, methods []string, err error)
- func AdminGetAuditLog(gdb *gorm.DB, id string) (db.AuditLog, error)
- func AdminGetCourse(gdb *gorm.DB, id string) (db.Course, error)
- func AdminGetForgejoRequest(gdb *gorm.DB, id string) (db.ForgejoRequest, error)
- func AdminListStudents(gdb *gorm.DB, courseID string) ([]db.Student, error)
- func AdminListTutors(gdb *gorm.DB, courseID string) ([]db.Tutor, error)
- func CanManageCourse(gdb *gorm.DB, c *echo.Context, courseID any) bool
- func CourseAccessScope(c *echo.Context) func(*gorm.DB) *gorm.DB
- func CourseManageScope(c *echo.Context) func(*gorm.DB) *gorm.DB
- func CreateAPIKey(gdb *gorm.DB, userID, name string) (db.ApiKey, string, error)
- func DeleteAPIKey(gdb *gorm.DB, userID string, keyID uint) error
- func EchoContext(ctx context.Context) *echo.Context
- func FetchCLIVersions() []string
- func IsTutorAssigned(gdb *gorm.DB, courseID, userID string) (bool, error)
- func ListAPIKeys(gdb *gorm.DB, userID string) ([]db.ApiKey, error)
- func ListExercisesForCourse(gdb *gorm.DB, courseID uint) ([]db.Exercise, error)
- func LoadCLIMinVersion(gdb *gorm.DB) string
- func Register[I, O any](h *Huma, op huma.Operation, handler func(context.Context, *I) (*O, error), ...)
- func ResolveUserID(gdb *gorm.DB, identifier string) (string, error)
- func RunTask(c *echo.Context, gdb *gorm.DB, name string) error
- func SearchUsersByNameOrEmail(gdb *gorm.DB, query string, limit int) ([]db.User, error)
- func SettingAccessScope(c *echo.Context) func(*gorm.DB) *gorm.DB
- func UserReadScope(c *echo.Context) func(*gorm.DB) *gorm.DB
- type AssignTutorBody
- type AuditLogFacets
- type AuditLogFacetsInput
- type AuditLogFacetsOutput
- type AuditLogGetInput
- type AuditLogGetOutput
- type AuditLogListInput
- type AuditLogListOutput
- type AuditLogListParams
- type AuditLogListQuery
- type AuditLogListResult
- type CLIVersionInput
- type CLIVersionOutput
- type ChartsCSVOutput
- type ChartsInput
- type ChartsOutput
- type ChartsResponse
- type CourseBody
- type CourseBrief
- type CourseListQuery
- type CourseStudentGradesInput
- type CourseStudentGradesOutput
- type CourseStudentListQuery
- type CourseTutorListQuery
- type CoursesCreateInput
- type CoursesCreateOutput
- type CoursesDeleteInput
- type CoursesDeleteOutput
- type CoursesGetInput
- type CoursesGetOutput
- type CoursesHardDeleteInput
- type CoursesHardDeleteOutput
- type CoursesJoinInput
- type CoursesJoinOutput
- type CoursesListInput
- type CoursesListOutput
- type CoursesListParams
- type CoursesListResult
- type CoursesRestoreInput
- type CoursesRestoreOutput
- type CoursesStudentsListInput
- type CoursesStudentsListOutput
- type CoursesStudentsMineInput
- type CoursesStudentsMineOutput
- type CoursesStudentsUnassignInput
- type CoursesStudentsUnassignOutput
- type CoursesTutorsAssignInput
- type CoursesTutorsAssignOutput
- type CoursesTutorsListInput
- type CoursesTutorsListOutput
- type CoursesTutorsUnassignInput
- type CoursesTutorsUnassignOutput
- type CoursesUpdateInput
- type CoursesUpdateOutput
- type CreateUserBody
- type CronJobResponse
- type CronListInput
- type CronListOutput
- type CronRunInput
- type CronRunOutput
- type ExerciseAllRow
- type ExerciseOut
- type ExercisesAllListParams
- type ExercisesAllListResult
- type ExercisesListInput
- type ExercisesListOutput
- type ForgejoRequestFacets
- type ForgejoRequestListParams
- type ForgejoRequestListQuery
- type ForgejoRequestListResult
- type ForgejoRequestsFacetsInput
- type ForgejoRequestsFacetsOutput
- type ForgejoRequestsListInput
- type ForgejoRequestsListOutput
- type ForgejoTimePoint
- type GradeBucket
- type GradeItem
- type GradedUngraded
- type HTTPError
- type Handler
- func (h *Handler) AttendanceHandler(c *echo.Context) error
- func (h *Handler) AuditLogFacets(ctx context.Context, input *AuditLogFacetsInput) (*AuditLogFacetsOutput, error)
- func (h *Handler) AuditLogGet(ctx context.Context, input *AuditLogGetInput) (*AuditLogGetOutput, error)
- func (h *Handler) AuditLogList(ctx context.Context, input *AuditLogListInput) (*AuditLogListOutput, error)
- func (h *Handler) CLIVersion(ctx context.Context, input *CLIVersionInput) (*CLIVersionOutput, error)
- func (h *Handler) Charts(ctx context.Context, input *ChartsInput) (*ChartsOutput, error)
- func (h *Handler) ChartsCSV(ctx context.Context, input *ChartsInput) (*ChartsCSVOutput, error)
- func (h *Handler) CourseStudentGrades(ctx context.Context, input *CourseStudentGradesInput) (*CourseStudentGradesOutput, error)
- func (h *Handler) CoursesCreate(ctx context.Context, input *CoursesCreateInput) (*CoursesCreateOutput, error)
- func (h *Handler) CoursesDelete(ctx context.Context, input *CoursesDeleteInput) (*CoursesDeleteOutput, error)
- func (h *Handler) CoursesGet(ctx context.Context, input *CoursesGetInput) (*CoursesGetOutput, error)
- func (h *Handler) CoursesHardDelete(ctx context.Context, input *CoursesHardDeleteInput) (*CoursesHardDeleteOutput, error)
- func (h *Handler) CoursesJoin(ctx context.Context, input *CoursesJoinInput) (*CoursesJoinOutput, error)
- func (h *Handler) CoursesList(ctx context.Context, input *CoursesListInput) (*CoursesListOutput, error)
- func (h *Handler) CoursesRestore(ctx context.Context, input *CoursesRestoreInput) (*CoursesRestoreOutput, error)
- func (h *Handler) CoursesStudentsList(ctx context.Context, input *CoursesStudentsListInput) (*CoursesStudentsListOutput, error)
- func (h *Handler) CoursesStudentsMine(ctx context.Context, input *CoursesStudentsMineInput) (*CoursesStudentsMineOutput, error)
- func (h *Handler) CoursesStudentsUnassign(ctx context.Context, input *CoursesStudentsUnassignInput) (*CoursesStudentsUnassignOutput, error)
- func (h *Handler) CoursesTutorsAssign(ctx context.Context, input *CoursesTutorsAssignInput) (*CoursesTutorsAssignOutput, error)
- func (h *Handler) CoursesTutorsList(ctx context.Context, input *CoursesTutorsListInput) (*CoursesTutorsListOutput, error)
- func (h *Handler) CoursesTutorsUnassign(ctx context.Context, input *CoursesTutorsUnassignInput) (*CoursesTutorsUnassignOutput, error)
- func (h *Handler) CoursesUpdate(ctx context.Context, input *CoursesUpdateInput) (*CoursesUpdateOutput, error)
- func (h *Handler) CronList(ctx context.Context, input *CronListInput) (*CronListOutput, error)
- func (h *Handler) CronRun(ctx context.Context, input *CronRunInput) (*CronRunOutput, error)
- func (h *Handler) ExercisesList(ctx context.Context, input *ExercisesListInput) (*ExercisesListOutput, error)
- func (h *Handler) ForgejoRequestsFacets(ctx context.Context, input *ForgejoRequestsFacetsInput) (*ForgejoRequestsFacetsOutput, error)
- func (h *Handler) ForgejoRequestsList(ctx context.Context, input *ForgejoRequestsListInput) (*ForgejoRequestsListOutput, error)
- func (h *Handler) GitPostRecieveHandler(c *echo.Context) error
- func (h *Handler) GitPreRecieveHandler(c *echo.Context) error
- func (h *Handler) SettingsCreate(ctx context.Context, input *SettingsCreateInput) (*SettingsCreateOutput, error)
- func (h *Handler) SettingsDelete(ctx context.Context, input *SettingsDeleteInput) (*SettingsDeleteOutput, error)
- func (h *Handler) SettingsGet(ctx context.Context, input *SettingsGetInput) (*SettingsGetOutput, error)
- func (h *Handler) SettingsList(ctx context.Context, input *SettingsListInput) (*SettingsListOutput, error)
- func (h *Handler) SettingsUpdate(ctx context.Context, input *SettingsUpdateInput) (*SettingsUpdateOutput, error)
- func (h *Handler) Stats(ctx context.Context, input *StatsInput) (*StatsOutput, error)
- func (h *Handler) TaskGet(ctx context.Context, input *TaskGetInput) (*TaskGetOutput, error)
- func (h *Handler) TaskList(ctx context.Context, input *TaskListInput) (*TaskListOutput, error)
- func (h *Handler) TaskRun(ctx context.Context, input *TaskRunInput) (*TaskRunOutput, error)
- func (h *Handler) UsersAdminList(ctx context.Context, input *UsersAdminListInput) (*UsersAdminListOutput, error)
- func (h *Handler) UsersCreate(ctx context.Context, input *UsersCreateInput) (*UsersCreateOutput, error)
- func (h *Handler) UsersDelete(ctx context.Context, input *UsersDeleteInput) (*UsersDeleteOutput, error)
- func (h *Handler) UsersDeleteSessions(ctx context.Context, input *UsersDeleteSessionsInput) (*UsersDeleteSessionsOutput, error)
- func (h *Handler) UsersGet(ctx context.Context, input *UsersGetInput) (*UsersGetOutput, error)
- func (h *Handler) UsersList(ctx context.Context, input *UsersListInput) (*UsersListOutput, error)
- func (h *Handler) UsersMe(ctx context.Context, input *UsersMeInput) (*UsersMeOutput, error)
- func (h *Handler) UsersMeCourses(ctx context.Context, input *UsersMeCoursesInput) (*UsersMeCoursesOutput, error)
- func (h *Handler) UsersMeGrades(ctx context.Context, input *UsersMeGradesInput) (*UsersMeGradesOutput, error)
- func (h *Handler) UsersMeRecentGrades(ctx context.Context, input *UsersMeRecentGradesInput) (*UsersMeRecentGradesOutput, error)
- func (h *Handler) UsersUpdate(ctx context.Context, input *UsersUpdateInput) (*UsersUpdateOutput, error)
- type Huma
- type LabelCount
- type MyCourseItem
- type RecentGradeItem
- type SemesterCount
- type SessionBrief
- type SettingBody
- type SettingListQuery
- type SettingsCreateInput
- type SettingsCreateOutput
- type SettingsDeleteInput
- type SettingsDeleteOutput
- type SettingsGetInput
- type SettingsGetOutput
- type SettingsListInput
- type SettingsListOutput
- type SettingsUpdateInput
- type SettingsUpdateOutput
- type StaffStatsResponse
- type StatsInput
- type StatsOutput
- type StatsResponse
- type StudentOut
- type TaskGetInput
- type TaskGetOutput
- type TaskListInput
- type TaskListOutput
- type TaskRunInput
- type TaskRunOutput
- type TimeSeries
- type TimeSeriesPoint
- type TutorOut
- type UpdateUserBody
- type UserAdminItem
- type UserBrief
- type UserListQuery
- type UsersAdminListInput
- type UsersAdminListOutput
- type UsersAdminListParams
- type UsersAdminListQuery
- type UsersAdminListResult
- type UsersCreateInput
- type UsersCreateOutput
- type UsersDeleteInput
- type UsersDeleteOutput
- type UsersDeleteSessionsInput
- type UsersDeleteSessionsOutput
- type UsersGetInput
- type UsersGetOutput
- type UsersListInput
- type UsersListOutput
- type UsersMeCoursesInput
- type UsersMeCoursesOutput
- type UsersMeGradesInput
- type UsersMeGradesOutput
- type UsersMeInput
- type UsersMeOutput
- type UsersMeRecentGradesInput
- type UsersMeRecentGradesOutput
- type UsersUpdateInput
- type UsersUpdateOutput
Constants ¶
const ( OrchestrationBotUserID = "bot-orchestration" OrchestrationBotUsername = "orchestration-bot" )
OrchestrationBotUserID / OrchestrationBotUsername identify the forgejo "orchestration-bot" account in the local DB. The bot creates every course org and repo on the owner's behalf. The same constants are declared in package db (the canonical home, since it owns the stub row); keep them in sync if either ever changes.
const CLIMinVersionSettingKey = "cli_min_version"
CLIMinVersionSettingKey is the settings key for the minimum CLI version.
Variables ¶
This section is empty.
Functions ¶
func AdminAuditLogFacets ¶
AdminAuditLogFacets returns distinct action and resource values present in the audit log, used to populate filter dropdowns.
func AdminForgejoRequestFacets ¶
AdminForgejoRequestFacets returns distinct source and method values present in the Forgejo request log.
func AdminGetAuditLog ¶
AdminGetAuditLog fetches a single audit log entry by ID.
func AdminGetCourse ¶
AdminGetCourse fetches a single course by ID (including archived courses via Unscoped, since the admin UI needs to show archived courses too).
func AdminGetForgejoRequest ¶
AdminGetForgejoRequest fetches a single Forgejo request by ID.
func AdminListStudents ¶
AdminListStudents fetches students for a course with users preloaded.
func AdminListTutors ¶
AdminListTutors fetches tutors for a course with users preloaded.
func CanManageCourse ¶
CanManageCourse reports whether the caller may manage the course identified by courseID. Admins always may; staff may only for courses they own. Used by handlers (e.g. HTML fragments) that operate on a course by id and need a boolean guard rather than a query scope.
func CourseAccessScope ¶
CourseAccessScope returns a GORM scope that filters courses based on the caller's role for *read* access. Admins see everything. Staff see joinable courses plus the courses they own. Everyone else (students and unauthenticated callers) sees only courses with allow_join = true.
func CourseManageScope ¶
CourseManageScope returns a GORM scope that restricts course queries to the courses the caller may *manage* (edit, delete, assign tutors/students, grade). Admins may manage every course; staff may manage only the courses they own; everyone else matches nothing. Applied to mutating course endpoints so a staff member acting on someone else's course gets a 404 rather than silently touching it.
func CreateAPIKey ¶
CreateAPIKey generates a new API key for the given user, stores the hash, and returns the model + the plaintext key (only visible at creation time). Keys expire after 1 year.
func DeleteAPIKey ¶
DeleteAPIKey deletes an API key, scoped to the given user.
func EchoContext ¶
EchoContext returns the echo context for the current huma request. Register injects it before the handler runs so handlers can build echo-context dependent GORM scopes and record audit entries. Returns nil when the handler is invoked outside of a registered operation (tests).
func FetchCLIVersions ¶
func FetchCLIVersions() []string
FetchCLIVersions fetches the available hopper-cli release versions from PyPI and returns them sorted descending (newest first) with a "v" prefix. Returns nil if PyPI is unreachable or the response cannot be parsed.
func IsTutorAssigned ¶
IsTutorAssigned returns true if userID is a tutor of courseID.
func ListAPIKeys ¶
ListAPIKeys returns all API keys for the given user, newest first.
func ListExercisesForCourse ¶
ListExercisesForCourse returns every exercise defined in a course, ordered by start date. Exported so tests and in-process callers can reuse the query without going through HTTP.
func LoadCLIMinVersion ¶
LoadCLIMinVersion reads the cli_min_version setting from the database, returning the stored value (with a "v" prefix if missing) or an empty string when the setting does not exist.
func Register ¶
func Register[I, O any](h *Huma, op huma.Operation, handler func(context.Context, *I) (*O, error), mw ...echo.MiddlewareFunc)
Register registers a huma operation with echo middleware applied as operation-level huma middleware, keeping route registration a one-liner:
api.Register(h, op, handler, a.Auth.RequireStaff())
The echo context of the current request is injected into the handler context and can be retrieved with EchoContext.
func ResolveUserID ¶
ResolveUserID resolves an arbitrary identifier to the canonical user PK (OIDC sub). Tries id, then preferred_username (case-insensitive), then student_id. Returns gorm.ErrRecordNotFound if nothing matches.
func RunTask ¶
RunTask triggers the named task. Returns an error if the task isn't found or fails. Records an audit entry on success. Exported for use by the HTML fragment handlers.
func SearchUsersByNameOrEmail ¶
SearchUsersByNameOrEmail returns up to limit users matching name or email. Used by the assign-tutor modal's user-search field.
func SettingAccessScope ¶
SettingAccessScope returns a GORM scope that filters settings by the caller's access level. Unauthenticated callers see only "public" entries. Regular authenticated users see "public" + "authed". Admins see everything.
func UserReadScope ¶
UserReadScope returns a GORM scope that restricts a users query to the rows the caller is allowed to *read*. Admins see everyone. Any other authenticated caller sees:
- themselves;
- (as course owner / staff) every student and tutor enrolled in a course they own;
- (as a course tutor) every student assigned to a tutor slot they hold.
The ownership branches are harmless for callers who own no courses and hold no tutor slots - their subqueries simply match nothing - so no role branch is needed beyond the admin short-circuit. Applied to the read endpoints so a staff member or tutor gets a scoped view instead of the whole user table, and a 404 (not a 403) for anyone outside their reach.
The whole predicate is a single grouped OR so it AND-combines cleanly with any search/filter scopes the list handler layers on top.
Types ¶
type AssignTutorBody ¶
type AssignTutorBody struct {
UserID string `json:"user_id"`
Description string `json:"description" required:"false"`
}
AssignTutorBody is the body for POST /courses/{id}/tutors.
type AuditLogFacets ¶
type AuditLogFacets struct {
Actions []string `json:"actions"`
Resources []string `json:"resources"`
}
AuditLogFacets is the response body of GET /audit-log/facets. Each field carries the distinct values currently present in the audit_logs table for the matching column, sorted ascending. Clients use it to populate filter dropdowns so we don't have to hardcode the list of actions in the UI every time a new audit call-site is added on the backend.
type AuditLogFacetsInput ¶
type AuditLogFacetsInput struct{}
AuditLogFacetsInput has no request parameters.
type AuditLogFacetsOutput ¶
type AuditLogFacetsOutput struct {
Body AuditLogFacets
}
AuditLogFacetsOutput holds the response body for AuditLogFacets.
type AuditLogGetInput ¶
type AuditLogGetInput struct {
ID string `path:"id"`
}
AuditLogGetInput holds the request parameters for AuditLogGet.
type AuditLogGetOutput ¶
AuditLogGetOutput holds the response body for AuditLogGet.
type AuditLogListInput ¶
type AuditLogListInput struct {
AuditLogListQuery
}
AuditLogListInput holds the request parameters for AuditLogList.
type AuditLogListOutput ¶
type AuditLogListOutput struct {
Body query.PaginatedResponse[db.AuditLog]
}
AuditLogListOutput holds the response body for AuditLogList.
type AuditLogListParams ¶
type AuditLogListParams struct {
Search string
Action string
Resource string
ActorID string
ResourceID string
Since string
Until string
SortBy string
SortDir string
Page int
PageSize int
}
AuditLogListParams holds the filter/sort/pagination inputs for the audit log list. Shared by the JSON API handler, the HTML fragment handler, and the page handler so all three paths agree on how params are read.
func ParseAuditLogListParams ¶
func ParseAuditLogListParams(c *echo.Context) AuditLogListParams
ParseAuditLogListParams extracts AuditLogListParams from query string.
type AuditLogListQuery ¶
type AuditLogListQuery struct {
Search string `query:"search" required:"false"`
Action string `query:"action" required:"false"`
Resource string `query:"resource" required:"false"`
ActorID string `query:"actor_id" required:"false"`
ResourceID string `query:"resource_id" required:"false"`
Since string `query:"since" required:"false"`
Until string `query:"until" required:"false"`
SortBy string `query:"sort_by" required:"false"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
AuditLogListQuery holds the filter/sort/pagination inputs for GET /audit-log. The query/default tags drive huma's request binding; the values are mapped into AuditLogListParams for the shared AdminListAuditLog query path.
type AuditLogListResult ¶
type AuditLogListResult struct {
Items []db.AuditLog
Total int64
Page int
PageSize int
TotalPages int
HasNext bool
HasPrev bool
}
AuditLogListResult holds the paginated result of an audit log list query.
func AdminListAuditLog ¶
func AdminListAuditLog(gdb *gorm.DB, p AuditLogListParams, loc *time.Location) (AuditLogListResult, error)
AdminListAuditLog runs the audit log list query with filters, sort, and pagination. Used by both the JSON API handler and the HTML fragment handler, one query path, two response formats. loc is the app timezone, used to interpret zone-less since/until filter values.
type CLIVersionInput ¶
type CLIVersionInput struct{}
CLIVersionInput holds the request parameters for CLIVersion (none).
type CLIVersionOutput ¶
type CLIVersionOutput struct {
Body cliVersionResponse
}
CLIVersionOutput holds the response body for CLIVersion.
type ChartsCSVOutput ¶
type ChartsCSVOutput struct {
ContentType string `header:"Content-Type"`
ContentDisposition string `header:"Content-Disposition"`
Body []byte
}
ChartsCSVOutput holds the response for ChartsCSV. The headers are bound via huma's output header fields so the raw CSV body keeps its content type.
type ChartsInput ¶
type ChartsInput struct {
CourseID uint64 `query:"course_id" required:"false"`
}
ChartsInput holds the request parameters for Charts and ChartsCSV.
type ChartsOutput ¶
type ChartsOutput struct {
Body ChartsResponse
}
ChartsOutput holds the response body for Charts.
type ChartsResponse ¶
type ChartsResponse struct {
UsersByFaculty []LabelCount `json:"users_by_faculty"`
RegistrationsOverTime []TimeSeriesPoint `json:"registrations_over_time"`
LoginsByDay []TimeSeriesPoint `json:"logins_by_day"`
LoginsByHour []LabelCount `json:"logins_by_hour"`
LoginsByWeekday []LabelCount `json:"logins_by_weekday"`
AuditActivityOverTime []TimeSeries `json:"audit_activity_over_time"`
ForgejoOverTime []ForgejoTimePoint `json:"forgejo_over_time"`
CoursesPerSemester []LabelCount `json:"courses_per_semester"`
StudentsPerTutor []LabelCount `json:"students_per_tutor"`
GradeDistPerExercise []GradeBucket `json:"grade_distribution_per_exercise"`
AvgScorePerExercise []LabelCount `json:"average_score_per_exercise"`
GradedVsUngraded []GradedUngraded `json:"graded_vs_ungraded_per_exercise"`
GradesByWeek []TimeSeriesPoint `json:"grades_by_week"`
AttendancePerWeek []TimeSeriesPoint `json:"attendance_per_week"`
PresentedVsAttended []LabelCount `json:"presented_vs_attended"`
EnrollmentsByFaculty []LabelCount `json:"enrollments_by_faculty"`
}
ChartsResponse contains all chart datasets for the stats page.
type CourseBody ¶
type CourseBody struct {
Name string `json:"name"`
Semester string `json:"semester"`
DisplayName string `json:"display_name" required:"false"`
Website string `json:"website" required:"false"`
BuilderImage string `json:"builder_image" required:"false"`
GraderImage string `json:"grader_image" required:"false"`
AllowPush bool `json:"allow_push" required:"false"`
AllowJoin bool `json:"allow_join" required:"false"`
RepoAccess string `json:"repo_access" required:"false"`
OwnerID string `json:"owner_id" required:"false"`
}
CourseBody is the request body for creating and updating courses. The id and timestamp fields are server-managed and not part of the payload. owner_id is accepted on create (admins may set it) and ignored on update.
type CourseBrief ¶
type CourseBrief struct {
ID uint `json:"id"`
Name string `json:"name"`
Semester string `json:"semester"`
DisplayName string `json:"display_name"`
}
CourseBrief is a minimal representation of a course for the admin UI.
func VisibleCourses ¶
func VisibleCourses(gdb *gorm.DB, ownerID string, isAdmin bool) []CourseBrief
VisibleCourses returns the courses the caller can see, for filter dropdowns: all courses for admins, owned courses for staff.
type CourseListQuery ¶
type CourseListQuery struct {
Search string `query:"search" required:"false"`
AllowJoin string `query:"allow_join" required:"false"`
AllowPush string `query:"allow_push" required:"false"`
Archived string `query:"archived" required:"false"`
Name string `query:"name" required:"false"`
Display string `query:"display_name" required:"false"`
Semester string `query:"semester" required:"false"`
SortBy string `query:"sort_by" required:"false"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
CourseListQuery holds the filter/sort/pagination inputs for GET /courses. The query/default tags drive huma's request binding; the values are mapped into CoursesListParams for the shared AdminListCourses query path. The boolean filters are strings because huma does not support pointer query parameters; boolParam converts them below.
type CourseStudentGradesInput ¶
type CourseStudentGradesInput struct {
CourseSlug string `path:"courseSlug"`
Username string `path:"username"`
}
CourseStudentGradesInput holds the request parameters for CourseStudentGrades. The course is addressed by its UID (Semester + "-" + Name, the Forgejo org name) and the student by their Forgejo username (users.preferred_username, the repo name), matching the <org>/<repo> layout of the course repositories.
type CourseStudentGradesOutput ¶
type CourseStudentGradesOutput struct {
Body []GradeItem
}
CourseStudentGradesOutput holds the response body for CourseStudentGrades.
type CourseStudentListQuery ¶
type CourseStudentListQuery struct {
SortBy string `query:"sort_by" required:"false" sort:"id,matrikelnummer" default_sort:"id asc"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
CourseStudentListQuery holds the pagination inputs for the course students list endpoint. The query/default tags drive huma's request binding; the sort/default_sort tags are ignored by huma and consumed by query.Scopes.
type CourseTutorListQuery ¶
type CourseTutorListQuery struct {
SortBy string `query:"sort_by" required:"false" sort:"id,created_at" default_sort:"id asc"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
CourseTutorListQuery holds the pagination inputs for the course tutors list endpoint. The query/default tags drive huma's request binding; the sort/default_sort tags are ignored by huma and consumed by query.Scopes.
type CoursesCreateInput ¶
type CoursesCreateInput struct {
Body CourseBody
}
type CoursesCreateOutput ¶
CoursesCreateOutput holds the response body for CoursesCreate.
type CoursesDeleteInput ¶
type CoursesDeleteInput struct {
ID string `path:"id"`
}
type CoursesDeleteOutput ¶
type CoursesDeleteOutput struct {
Status int
}
CoursesDeleteOutput holds the response status for CoursesDelete.
type CoursesGetInput ¶
type CoursesGetInput struct {
ID string `path:"id"`
}
CoursesGetInput holds the request parameters for CoursesGet.
type CoursesGetOutput ¶
CoursesGetOutput holds the response body for CoursesGet.
type CoursesHardDeleteInput ¶
type CoursesHardDeleteInput struct {
ID string `path:"id"`
}
type CoursesHardDeleteOutput ¶
type CoursesHardDeleteOutput struct {
Status int
}
CoursesHardDeleteOutput holds the response status for CoursesHardDelete.
type CoursesJoinInput ¶
type CoursesJoinInput struct {
ID string `path:"id"`
}
CoursesJoinInput holds the request parameters for CoursesJoin.
type CoursesJoinOutput ¶
CoursesJoinOutput holds the response body for CoursesJoin.
type CoursesListInput ¶
type CoursesListInput struct {
CourseListQuery
}
CoursesListInput holds the request parameters for CoursesList.
type CoursesListOutput ¶
type CoursesListOutput struct {
Body query.PaginatedResponse[db.Course]
}
CoursesListOutput holds the response body for CoursesList.
type CoursesListParams ¶
type CoursesListParams struct {
Search string
AllowJoin *bool
AllowPush *bool
Archived *bool
Name string
Display string
Semester string
SortBy string
SortDir string
Page int
PageSize int
}
CoursesListParams holds the filter/sort/pagination inputs for the admin courses list. Shared by the JSON API handler, the HTML fragment handler, and the page handler so all three paths agree on how params are read.
func ParseCoursesListParams ¶
func ParseCoursesListParams(c *echo.Context) CoursesListParams
ParseCoursesListParams extracts CoursesListParams from query string. Shared by the JSON API handler, the HTML fragment handler, and the page handler so all three paths agree on how params are read.
type CoursesListResult ¶
type CoursesListResult struct {
Items []db.Course
Total int64
Page int
PageSize int
TotalPages int
HasNext bool
HasPrev bool
}
CoursesListResult holds the paginated result of an admin courses list query.
func AdminListCourses ¶
func AdminListCourses(gdb *gorm.DB, p CoursesListParams) (CoursesListResult, error)
AdminListCourses runs the courses list query with filters, sort, and pagination. Used by both the JSON API handler and the HTML fragment handler, one query path, two response formats. Always returns both active and archived courses (use Archived to filter).
type CoursesRestoreInput ¶
type CoursesRestoreInput struct {
ID string `path:"id"`
}
type CoursesRestoreOutput ¶
CoursesRestoreOutput holds the response body for CoursesRestore.
type CoursesStudentsListInput ¶
type CoursesStudentsListInput struct {
ID string `path:"id"`
CourseStudentListQuery
}
CoursesStudentsListInput holds the request parameters for CoursesStudentsList.
type CoursesStudentsListOutput ¶
type CoursesStudentsListOutput struct {
Body query.PaginatedResponse[StudentOut]
}
CoursesStudentsListOutput holds the response body for CoursesStudentsList.
type CoursesStudentsMineInput ¶
type CoursesStudentsMineInput struct {
ID string `path:"id"`
}
CoursesStudentsMineInput holds the request parameters for CoursesStudentsMine.
type CoursesStudentsMineOutput ¶
type CoursesStudentsMineOutput struct {
Body []StudentOut
}
CoursesStudentsMineOutput holds the response body for CoursesStudentsMine.
type CoursesStudentsUnassignInput ¶
CoursesStudentsUnassignInput holds the request parameters for CoursesStudentsUnassign.
type CoursesStudentsUnassignOutput ¶
type CoursesStudentsUnassignOutput struct {
Status int
}
CoursesStudentsUnassignOutput holds the response status for CoursesStudentsUnassign.
type CoursesTutorsAssignInput ¶
type CoursesTutorsAssignInput struct {
ID string `path:"id"`
Body AssignTutorBody
}
CoursesTutorsAssignInput holds the request parameters for CoursesTutorsAssign.
type CoursesTutorsAssignOutput ¶
type CoursesTutorsAssignOutput struct {
Body TutorOut
}
CoursesTutorsAssignOutput holds the response body for CoursesTutorsAssign.
type CoursesTutorsListInput ¶
type CoursesTutorsListInput struct {
ID string `path:"id"`
CourseTutorListQuery
}
CoursesTutorsListInput holds the request parameters for CoursesTutorsList.
type CoursesTutorsListOutput ¶
type CoursesTutorsListOutput struct {
Body query.PaginatedResponse[TutorOut]
}
CoursesTutorsListOutput holds the response body for CoursesTutorsList.
type CoursesTutorsUnassignInput ¶
CoursesTutorsUnassignInput holds the request parameters for CoursesTutorsUnassign.
type CoursesTutorsUnassignOutput ¶
type CoursesTutorsUnassignOutput struct {
Status int
}
CoursesTutorsUnassignOutput holds the response status for CoursesTutorsUnassign.
type CoursesUpdateInput ¶
type CoursesUpdateInput struct {
ID string `path:"id"`
Body CourseBody
}
type CoursesUpdateOutput ¶
CoursesUpdateOutput holds the response body for CoursesUpdate.
type CreateUserBody ¶
type CreateUserBody struct {
Email string `json:"email" required:"false"`
Name string `json:"name"`
Subject string `json:"subject" required:"false"`
PreferredUsername string `json:"preferred_username" required:"false"`
StudentID string `json:"student_id" required:"false"`
AccountType string `json:"account_type" required:"false"`
Faculty string `json:"faculty" required:"false"`
EnrolledSubject string `json:"enrolled_subject" required:"false"`
ExtraClaims string `json:"extra_claims" required:"false"`
Role db.Role `json:"role" required:"false"`
}
CreateUserBody is the request body for creating a user. The id and the timestamp fields are server-managed and not part of the payload.
type CronJobResponse ¶
type CronJobResponse struct {
ID string `json:"id"`
Name string `json:"name"`
Tags []string `json:"tags"`
IsRunning bool `json:"is_running"`
LastRunStartedAt *time.Time `json:"last_run_started_at,omitempty"`
LastRunCompletedAt *time.Time `json:"last_run_completed_at,omitempty"`
NextRun *time.Time `json:"next_run,omitempty"`
NextRuns []time.Time `json:"next_runs,omitempty"`
Schedule any `json:"schedule,omitempty"` // optional, see below
}
func ListCronJobs ¶
func ListCronJobs(scheduler gocron.Scheduler) []CronJobResponse
ListCronJobs is the exported version of listCronJobs, for use by the HTML fragment handlers (which have access to *app.App but not *api.Handler).
type CronListInput ¶
type CronListInput struct{}
CronListInput holds the request parameters for CronList (none).
type CronListOutput ¶
type CronListOutput struct {
Body []CronJobResponse
}
CronListOutput holds the response body for CronList.
type CronRunInput ¶
type CronRunInput struct {
ID string `path:"id"`
}
CronRunInput holds the request parameters for CronRun.
type CronRunOutput ¶
type CronRunOutput struct {
Body CronJobResponse
}
CronRunOutput holds the response body for CronRun.
type ExerciseAllRow ¶
type ExerciseAllRow struct {
ID uint `json:"id"`
Name string `json:"name"`
CourseID uint `json:"course_id"`
CourseName string `json:"course_name"`
Semester string `json:"semester"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
Points *float64 `json:"points"`
UngradedCount int64 `json:"ungraded_count"`
}
ExerciseAllRow is one exercise with its course and the number of submissions that still need grading (points IS NULL).
type ExerciseOut ¶
type ExerciseOut struct {
ID uint `json:"id"`
Name string `json:"name"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
Points *float64 `json:"points"`
CourseID uint `json:"course_id"`
}
ExerciseOut is the public shape of an exercise returned by the build/ grading lookup endpoint. It mirrors the subset of db.Exercise that an external consumer (the build/grading service) needs to decide whether a build is eligible and to pick a pre-deadline commit. It is a separate type from db.Exercise so we never accidentally leak internal fields.
type ExercisesAllListParams ¶
type ExercisesAllListParams struct {
Search string
CourseID string
SortBy string
SortDir string
Page int
PageSize int
}
ExercisesAllListParams holds the filter/sort/pagination inputs for the cross-course exercises list. Shared by the page handler and the HTML fragment handler.
func ParseExercisesAllListParams ¶
func ParseExercisesAllListParams(c *echo.Context) ExercisesAllListParams
ParseExercisesAllListParams extracts ExercisesAllListParams from the query string.
type ExercisesAllListResult ¶
type ExercisesAllListResult struct {
Items []ExerciseAllRow
Total int64
Page int
PageSize int
TotalPages int
HasNext bool
HasPrev bool
}
ExercisesAllListResult holds the paginated result of the cross-course exercises list.
func AdminListExercisesAll ¶
func AdminListExercisesAll(gdb *gorm.DB, p ExercisesAllListParams) (ExercisesAllListResult, error)
AdminListExercisesAll lists exercises across all courses.
func ScopedListExercisesAll ¶
func ScopedListExercisesAll(gdb *gorm.DB, p ExercisesAllListParams, ownerID string) (ExercisesAllListResult, error)
ScopedListExercisesAll lists exercises restricted to courses owned by the given staff member.
type ExercisesListInput ¶
type ExercisesListInput struct {
ID string `path:"id"`
}
ExercisesListInput holds the request parameters for ExercisesList.
type ExercisesListOutput ¶
type ExercisesListOutput struct {
Body []ExerciseOut
}
ExercisesListOutput holds the response body for ExercisesList.
type ForgejoRequestFacets ¶
type ForgejoRequestFacets struct {
Sources []string `json:"sources"`
Methods []string `json:"methods"`
}
ForgejoRequestFacets is the response body of GET /forgejo-requests/facets. Each field carries the distinct values currently present in the forgejo_requests table, sorted ascending; the UI uses them to populate filter dropdowns.
type ForgejoRequestListParams ¶
type ForgejoRequestListParams struct {
Search string
Source string
Method string
MinStatus string
MaxStatus string
Since string
Until string
SortBy string
SortDir string
Page int
PageSize int
}
ForgejoRequestListParams holds the filter/sort/pagination inputs for the Forgejo request log list. Shared by the JSON API handler, the HTML fragment handler, and the page handler.
func ParseForgejoRequestListParams ¶
func ParseForgejoRequestListParams(c *echo.Context) ForgejoRequestListParams
ParseForgejoRequestListParams extracts ForgejoRequestListParams from query string.
type ForgejoRequestListQuery ¶
type ForgejoRequestListQuery struct {
Search string `query:"search" required:"false"`
Source string `query:"source" required:"false"`
Method string `query:"method" required:"false"`
MinStatus string `query:"min_status" required:"false"`
MaxStatus string `query:"max_status" required:"false"`
Since string `query:"since" required:"false"`
Until string `query:"until" required:"false"`
SortBy string `query:"sort_by" required:"false"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
ForgejoRequestListQuery holds the filter/sort/pagination inputs for GET /forgejo-requests. The query/default tags drive huma's request binding; the values are mapped into ForgejoRequestListParams for the shared AdminListForgejoRequests query path.
type ForgejoRequestListResult ¶
type ForgejoRequestListResult struct {
Items []db.ForgejoRequest
Total int64
Page int
PageSize int
TotalPages int
HasNext bool
HasPrev bool
}
ForgejoRequestListResult holds the paginated result of a Forgejo request list query.
func AdminListForgejoRequests ¶
func AdminListForgejoRequests(gdb *gorm.DB, p ForgejoRequestListParams, loc *time.Location) (ForgejoRequestListResult, error)
AdminListForgejoRequests runs the Forgejo request list query with filters, sort, and pagination. Used by both the JSON API handler and the HTML fragment handler.
type ForgejoRequestsFacetsInput ¶
type ForgejoRequestsFacetsInput struct{}
ForgejoRequestsFacetsInput has no request parameters.
type ForgejoRequestsFacetsOutput ¶
type ForgejoRequestsFacetsOutput struct {
Body ForgejoRequestFacets
}
ForgejoRequestsFacetsOutput holds the response body for ForgejoRequestsFacets.
type ForgejoRequestsListInput ¶
type ForgejoRequestsListInput struct {
ForgejoRequestListQuery
}
ForgejoRequestsListInput holds the request parameters for ForgejoRequestsList.
type ForgejoRequestsListOutput ¶
type ForgejoRequestsListOutput struct {
Body query.PaginatedResponse[db.ForgejoRequest]
}
ForgejoRequestsListOutput holds the response body for ForgejoRequestsList.
type ForgejoTimePoint ¶
type ForgejoTimePoint struct {
Date string `json:"date"`
Success int64 `json:"success"`
Error int64 `json:"error"`
AvgLatency int64 `json:"avg_latency_ms"`
}
ForgejoTimePoint combines request counts and latency for a single day.
type GradeBucket ¶
type GradeBucket struct {
Exercise string `json:"exercise"`
Bucket string `json:"bucket"`
Count int64 `json:"count"`
}
GradeBucket is one bucket of the grade-distribution histogram for an exercise.
type GradeItem ¶
type GradeItem struct {
ExerciseName string `json:"exercise_name"`
CourseName string `json:"course_name"`
CourseSlug string `json:"course_slug"`
CourseID uint `json:"course_id"`
Points *float64 `json:"points"`
MaxPoints *float64 `json:"max_points"`
GradedAt *time.Time `json:"graded_at"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
}
GradeItem is one exercise entry for the /users/me/grades overview. Unlike RecentGradeItem it also covers exercises that have not been graded yet (no student_exercises row, or one with NULL points): for those points and graded_at are null. Start/End are the exercise's time window so the frontend can render countdowns to the deadline.
type GradedUngraded ¶
type GradedUngraded struct {
Exercise string `json:"exercise"`
Graded int64 `json:"graded"`
Ungraded int64 `json:"ungraded"`
}
GradedUngraded pairs graded and ungraded counts for a single exercise.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
func (*Handler) AttendanceHandler ¶
AttendanceHandler handles POST /api/attendance. A tutor scans a student's QR code (which encodes the student's user ID); this logs a TutorialParticipation record for today. The caller must be a tutor of the given course.
Students assigned to this tutor can check in once per day. Students enrolled in the course but assigned to a different tutor (or no tutor) are "guests" and can attend once per course per week. Students not enrolled in the course at all are rejected.
func (*Handler) AuditLogFacets ¶
func (h *Handler) AuditLogFacets(ctx context.Context, input *AuditLogFacetsInput) (*AuditLogFacetsOutput, error)
AuditLogFacets returns the distinct action and resource values currently present in the audit log, used to populate filter dropdowns (admin only).
func (*Handler) AuditLogGet ¶
func (h *Handler) AuditLogGet(ctx context.Context, input *AuditLogGetInput) (*AuditLogGetOutput, error)
AuditLogGet returns a single audit log entry by ID (admin only).
func (*Handler) AuditLogList ¶
func (h *Handler) AuditLogList(ctx context.Context, input *AuditLogListInput) (*AuditLogListOutput, error)
AuditLogList returns a paginated list of audit log entries, newest first, filterable by action, resource, actor and time range (admin only).
func (*Handler) CLIVersion ¶
func (h *Handler) CLIVersion(ctx context.Context, input *CLIVersionInput) (*CLIVersionOutput, error)
CLIVersion returns the minimum required hopper-cli version from the "cli_min_version" setting. Public endpoint; no authentication required.
func (*Handler) Charts ¶
func (h *Handler) Charts(ctx context.Context, input *ChartsInput) (*ChartsOutput, error)
Charts returns all chart datasets (overview, per-course, cross-dimensional) as JSON. When course_id is present and non-zero, per-course charts filter to that course; overview and cross-dimensional charts are always unfiltered.
func (*Handler) ChartsCSV ¶
func (h *Handler) ChartsCSV(ctx context.Context, input *ChartsInput) (*ChartsCSVOutput, error)
ChartsCSV returns a CSV file containing all chart datasets, one section per chart separated by a blank line. When course_id is present and non-zero, per-course charts filter to that course.
func (*Handler) CourseStudentGrades ¶
func (h *Handler) CourseStudentGrades(ctx context.Context, input *CourseStudentGradesInput) (*CourseStudentGradesOutput, error)
CourseStudentGrades returns all exercises of one course for one student, including ungraded ones (points and graded_at are null for those), with the same item shape as UsersMeGrades. The course is resolved by its UID and the student by their Forgejo username. Access is limited to the student themselves and course staff (course owner, admins, tutors of that course); anyone else signed in gets 403, unknown courses or students 404.
func (*Handler) CoursesCreate ¶
func (h *Handler) CoursesCreate(ctx context.Context, input *CoursesCreateInput) (*CoursesCreateOutput, error)
CoursesCreate creates a new course (staff only).
func (*Handler) CoursesDelete ¶
func (h *Handler) CoursesDelete(ctx context.Context, input *CoursesDeleteInput) (*CoursesDeleteOutput, error)
CoursesDelete deletes a course by ID (soft delete, staff only).
func (*Handler) CoursesGet ¶
func (h *Handler) CoursesGet(ctx context.Context, input *CoursesGetInput) (*CoursesGetOutput, error)
CoursesGet returns a single course by ID. Non-admin users see only joinable courses.
func (*Handler) CoursesHardDelete ¶
func (h *Handler) CoursesHardDelete(ctx context.Context, input *CoursesHardDeleteInput) (*CoursesHardDeleteOutput, error)
CoursesHardDelete permanently removes an archived course and all of its data from the database. Only courses that are already soft-deleted (archived) can be hard-deleted (admin only).
func (*Handler) CoursesJoin ¶
func (h *Handler) CoursesJoin(ctx context.Context, input *CoursesJoinInput) (*CoursesJoinOutput, error)
CoursesJoin enrolls the authenticated user as a student in the given course. The course must have allow_join enabled. When Forgejo is configured, the user is required to have an account on the Forgejo instance (the local part of their email is used as the username); otherwise the request is rejected with 409.
func (*Handler) CoursesList ¶
func (h *Handler) CoursesList(ctx context.Context, input *CoursesListInput) (*CoursesListOutput, error)
CoursesList returns a paginated list of courses. Non-admin users see only joinable courses.
func (*Handler) CoursesRestore ¶
func (h *Handler) CoursesRestore(ctx context.Context, input *CoursesRestoreInput) (*CoursesRestoreOutput, error)
CoursesRestore restores a soft-deleted (archived) course by clearing its deleted_at (staff only).
func (*Handler) CoursesStudentsList ¶
func (h *Handler) CoursesStudentsList(ctx context.Context, input *CoursesStudentsListInput) (*CoursesStudentsListOutput, error)
CoursesStudentsList returns a paginated list of students enrolled in a specific course. Only callers who may manage the course get access.
func (*Handler) CoursesStudentsMine ¶
func (h *Handler) CoursesStudentsMine(ctx context.Context, input *CoursesStudentsMineInput) (*CoursesStudentsMineOutput, error)
CoursesStudentsMine returns the students assigned to the authenticated tutor in the given course. Admins and the course owner see all students; tutors see only those assigned to their tutor slot. Each student includes a trimmed user profile (id, name, preferred_username; the Forgejo repo name).
func (*Handler) CoursesStudentsUnassign ¶
func (h *Handler) CoursesStudentsUnassign(ctx context.Context, input *CoursesStudentsUnassignInput) (*CoursesStudentsUnassignOutput, error)
CoursesStudentsUnassign removes a user's enrollment from the given course (staff only).
func (*Handler) CoursesTutorsAssign ¶
func (h *Handler) CoursesTutorsAssign(ctx context.Context, input *CoursesTutorsAssignInput) (*CoursesTutorsAssignOutput, error)
CoursesTutorsAssign assigns an existing user as a tutor of the given course (staff only).
func (*Handler) CoursesTutorsList ¶
func (h *Handler) CoursesTutorsList(ctx context.Context, input *CoursesTutorsListInput) (*CoursesTutorsListOutput, error)
CoursesTutorsList returns a paginated list of tutors assigned to a specific course. Only callers who may manage the course get access.
func (*Handler) CoursesTutorsUnassign ¶
func (h *Handler) CoursesTutorsUnassign(ctx context.Context, input *CoursesTutorsUnassignInput) (*CoursesTutorsUnassignOutput, error)
CoursesTutorsUnassign removes a user as a tutor of the given course (staff only).
func (*Handler) CoursesUpdate ¶
func (h *Handler) CoursesUpdate(ctx context.Context, input *CoursesUpdateInput) (*CoursesUpdateOutput, error)
CoursesUpdate updates an existing course by ID. Staff may only update the courses they own.
func (*Handler) CronList ¶
func (h *Handler) CronList(ctx context.Context, input *CronListInput) (*CronListOutput, error)
CronList returns a list of all jobs regularly run by the orchestration app.
func (*Handler) CronRun ¶
func (h *Handler) CronRun(ctx context.Context, input *CronRunInput) (*CronRunOutput, error)
CronRun triggers the given job to run immediately without waiting for its next scheduled execution.
func (*Handler) ExercisesList ¶
func (h *Handler) ExercisesList(ctx context.Context, input *ExercisesListInput) (*ExercisesListOutput, error)
ExercisesList returns the exercises defined in a course, ordered by start date. Used by the build/grading service to resolve exercise deadlines without duplicating the exercise table.
func (*Handler) ForgejoRequestsFacets ¶
func (h *Handler) ForgejoRequestsFacets(ctx context.Context, input *ForgejoRequestsFacetsInput) (*ForgejoRequestsFacetsOutput, error)
ForgejoRequestsFacets returns the distinct source and method values currently present in the Forgejo request log, used to populate filter dropdowns (admin only).
func (*Handler) ForgejoRequestsList ¶
func (h *Handler) ForgejoRequestsList(ctx context.Context, input *ForgejoRequestsListInput) (*ForgejoRequestsListOutput, error)
ForgejoRequestsList returns a paginated list of every outgoing Forgejo HTTP request the orchestrator has made (most recent first), with full request and response envelopes (admin only).
func (*Handler) GitPostRecieveHandler ¶
func (*Handler) GitPreRecieveHandler ¶
func (*Handler) SettingsCreate ¶
func (h *Handler) SettingsCreate(ctx context.Context, input *SettingsCreateInput) (*SettingsCreateOutput, error)
SettingsCreate creates a new setting (admin only).
func (*Handler) SettingsDelete ¶
func (h *Handler) SettingsDelete(ctx context.Context, input *SettingsDeleteInput) (*SettingsDeleteOutput, error)
SettingsDelete deletes a setting by key (admin only).
func (*Handler) SettingsGet ¶
func (h *Handler) SettingsGet(ctx context.Context, input *SettingsGetInput) (*SettingsGetOutput, error)
SettingsGet returns a single setting by key if visible to the caller.
func (*Handler) SettingsList ¶
func (h *Handler) SettingsList(ctx context.Context, input *SettingsListInput) (*SettingsListOutput, error)
SettingsList returns a paginated list of settings visible to the caller.
func (*Handler) SettingsUpdate ¶
func (h *Handler) SettingsUpdate(ctx context.Context, input *SettingsUpdateInput) (*SettingsUpdateOutput, error)
SettingsUpdate updates an existing setting by key (admin only).
func (*Handler) Stats ¶
func (h *Handler) Stats(ctx context.Context, input *StatsInput) (*StatsOutput, error)
Stats returns the aggregate dashboard statistics (admin only).
func (*Handler) TaskGet ¶
func (h *Handler) TaskGet(ctx context.Context, input *TaskGetInput) (*TaskGetOutput, error)
TaskGet returns details for a single registered task.
func (*Handler) TaskList ¶
func (h *Handler) TaskList(ctx context.Context, input *TaskListInput) (*TaskListOutput, error)
TaskList returns a list of all registered tasks that can be run manually.
func (*Handler) TaskRun ¶
func (h *Handler) TaskRun(ctx context.Context, input *TaskRunInput) (*TaskRunOutput, error)
TaskRun triggers a registered task to run immediately.
func (*Handler) UsersAdminList ¶
func (h *Handler) UsersAdminList(ctx context.Context, input *UsersAdminListInput) (*UsersAdminListOutput, error)
UsersAdminList returns a paginated list of users with their session count, last login, recent sessions, and course relationships (admin only).
func (*Handler) UsersCreate ¶
func (h *Handler) UsersCreate(ctx context.Context, input *UsersCreateInput) (*UsersCreateOutput, error)
UsersCreate creates a new user (admin only).
func (*Handler) UsersDelete ¶
func (h *Handler) UsersDelete(ctx context.Context, input *UsersDeleteInput) (*UsersDeleteOutput, error)
UsersDelete deletes a user by ID (admin only).
func (*Handler) UsersDeleteSessions ¶
func (h *Handler) UsersDeleteSessions(ctx context.Context, input *UsersDeleteSessionsInput) (*UsersDeleteSessionsOutput, error)
UsersDeleteSessions deletes all active OIDC sessions for the specified user, forcing them to re-authenticate on their next request (admin only).
func (*Handler) UsersGet ¶
func (h *Handler) UsersGet(ctx context.Context, input *UsersGetInput) (*UsersGetOutput, error)
UsersGet returns a single user by ID. Non-admin callers may only read users they are related to (staff: members of their courses; tutors: their assigned students; anyone: themselves); others get 404.
func (*Handler) UsersList ¶
func (h *Handler) UsersList(ctx context.Context, input *UsersListInput) (*UsersListOutput, error)
UsersList returns a paginated list of users matching the requested filters. Non-admin callers only see users they are related to: staff see the students and tutors of the courses they own, tutors see their assigned students, and everyone always sees themselves.
func (*Handler) UsersMe ¶
func (h *Handler) UsersMe(ctx context.Context, input *UsersMeInput) (*UsersMeOutput, error)
UsersMe returns the authenticated user for the currently signed-in user.
func (*Handler) UsersMeCourses ¶
func (h *Handler) UsersMeCourses(ctx context.Context, input *UsersMeCoursesInput) (*UsersMeCoursesOutput, error)
UsersMeCourses returns the courses in which the authenticated user is a student or a tutor. Each entry carries a `role` field ("student" or "tutor") so the caller can pick the right action. Archived (soft-deleted) courses are excluded.
func (*Handler) UsersMeGrades ¶
func (h *Handler) UsersMeGrades(ctx context.Context, input *UsersMeGradesInput) (*UsersMeGradesOutput, error)
UsersMeGrades returns all exercises of the courses the authenticated user is enrolled in as a student, including ungraded ones (points and graded_at are null for those). Items are ordered by course name, then by exercise start, end, and name.
func (*Handler) UsersMeRecentGrades ¶
func (h *Handler) UsersMeRecentGrades(ctx context.Context, input *UsersMeRecentGradesInput) (*UsersMeRecentGradesOutput, error)
UsersMeRecentGrades returns the 5 most recently graded exercises for the authenticated user.
func (*Handler) UsersUpdate ¶
func (h *Handler) UsersUpdate(ctx context.Context, input *UsersUpdateInput) (*UsersUpdateOutput, error)
UsersUpdate updates an existing user by ID (admin only).
type Huma ¶
Huma holds the huma API mounted on the shared echo instance.
func NewHuma ¶
NewHuma builds the huma API on top of the given echo instance. The API metadata comes from the resolved config (API_HOST, API_TERMS, API_SUPPORT_* env vars, read once at startup). Huma serves the generated spec itself at /api/openapi.json and /api/openapi.yaml and the docs UI at /api/docs. The schema endpoint is disabled because the spec embeds all schemas.
func (*Huma) UseAuth ¶
func (h *Huma) UseAuth(mw ...echo.MiddlewareFunc) huma.Middlewares
UseAuth converts echo middleware (a.Auth.Require, RequireStaff, ...) into huma middleware for one operation. The middleware runs against the unwrapped echo context; if it short-circuits with an error, the error is rendered by echo's existing error handler unchanged and the huma handler is never invoked.
type LabelCount ¶
LabelCount is a generic label/count pair for categorical chart data.
type MyCourseItem ¶
MyCourseItem pairs a full course with the role the current user has in it (student or tutor). Used by /users/me/courses so the dashboard template can render the right action per role.
type RecentGradeItem ¶
type RecentGradeItem struct {
ExerciseName string `json:"exercise_name"`
CourseName string `json:"course_name"`
CourseSlug string `json:"course_slug"`
CourseID uint `json:"course_id"`
Points *float64 `json:"points"`
MaxPoints *float64 `json:"max_points"`
GradedAt time.Time `json:"graded_at"`
}
RecentGradeItem is a grade record for the dashboard "Recently Graded" list.
type SemesterCount ¶
SemesterCount pairs a semester identifier with the number of courses in it.
type SessionBrief ¶
type SessionBrief struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
}
SessionBrief is a minimal representation of an OIDC session for the admin UI.
type SettingBody ¶
type SettingBody struct {
Key string `json:"key"`
Value string `json:"value"`
Type string `json:"type" required:"false"`
Access string `json:"access" required:"false"`
}
SettingBody is the request body for creating and updating settings. Timestamps are server-managed and not part of the payload.
type SettingListQuery ¶
type SettingListQuery struct {
Key string `query:"key" required:"false" filter:"key"`
Type string `query:"type" required:"false" filter:"type"`
Access string `query:"access" required:"false" filter:"access"`
Search string `query:"search" required:"false" search:"key,value"`
SortBy string `query:"sort_by" required:"false" sort:"key,access,created_at,updated_at"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
SettingListQuery holds the filter/sort/pagination inputs for GET /settings. The query/default tags drive huma's request binding; the filter/search/sort tags are ignored by huma and consumed by query.Scopes.
type SettingsCreateInput ¶
type SettingsCreateInput struct {
Body SettingBody
}
SettingsCreateInput holds the request parameters for SettingsCreate.
type SettingsCreateOutput ¶
SettingsCreateOutput holds the response body for SettingsCreate.
type SettingsDeleteInput ¶
type SettingsDeleteInput struct {
Key string `path:"key"`
}
SettingsDeleteInput holds the request parameters for SettingsDelete.
type SettingsDeleteOutput ¶
type SettingsDeleteOutput struct {
Status int
}
SettingsDeleteOutput holds the response status for SettingsDelete.
type SettingsGetInput ¶
type SettingsGetInput struct {
Key string `path:"key"`
}
SettingsGetInput holds the request parameters for SettingsGet.
type SettingsGetOutput ¶
SettingsGetOutput holds the response body for SettingsGet.
type SettingsListInput ¶
type SettingsListInput struct {
SettingListQuery
}
SettingsListInput holds the request parameters for SettingsList.
type SettingsListOutput ¶
type SettingsListOutput struct {
Body query.PaginatedResponse[db.Setting]
}
SettingsListOutput holds the response body for SettingsList.
type SettingsUpdateInput ¶
type SettingsUpdateInput struct {
Key string `path:"key"`
Body SettingBody
}
SettingsUpdateInput holds the request parameters for SettingsUpdate.
type SettingsUpdateOutput ¶
SettingsUpdateOutput holds the response body for SettingsUpdate.
type StaffStatsResponse ¶
type StaffStatsResponse struct {
MyCourses int64 `json:"my_courses"`
JoinableCourses int64 `json:"joinable_courses"`
ArchivedCourses int64 `json:"archived_courses"`
SemesterBreakdown []SemesterCount `json:"semester_breakdown"`
MyStudents int64 `json:"my_students"`
MyTutors int64 `json:"my_tutors"`
MyExercises int64 `json:"my_exercises"`
}
StaffStatsResponse holds dashboard stats scoped to a single staff member.
func ComputeStaffStats ¶
func ComputeStaffStats(gdb *gorm.DB, userID string) StaffStatsResponse
ComputeStaffStats aggregates dashboard statistics scoped to the courses owned by the given user ID.
type StatsInput ¶
type StatsInput struct{}
StatsInput holds the request parameters for Stats (none).
type StatsOutput ¶
type StatsOutput struct {
Body StatsResponse
}
StatsOutput holds the response body for Stats.
type StatsResponse ¶
type StatsResponse struct {
TotalUsers int64 `json:"total_users"`
StaffUsers int64 `json:"total_staff"`
AdminUsers int64 `json:"admin_users"`
TotalCourses int64 `json:"total_courses"`
JoinableCourses int64 `json:"joinable_courses"`
ArchivedCourses int64 `json:"archived_courses"`
TotalStudents int64 `json:"total_students"`
TotalTutors int64 `json:"total_tutors"`
TotalAuditLogs int64 `json:"total_audit_logs"`
TotalExercises int64 `json:"total_exercises"`
ActiveSessions int64 `json:"active_sessions"`
TotalTasks int64 `json:"total_tasks"`
TotalCronJobs int64 `json:"total_cron_jobs"`
OrphanOrgs int64 `json:"orphan_orgs"`
SemesterBreakdown []SemesterCount `json:"semester_breakdown"`
}
StatsResponse is the response body of GET /stats. It aggregates counts across the major tables and includes a Forgejo orphan-org count when the Forgejo client is configured.
func ComputeStats ¶
func ComputeStats(gdb *gorm.DB, scheduler jobsLister) StatsResponse
ComputeStats aggregates dashboard statistics. Exported so the HTML fragment handler (which has *app.App but not *api.Handler) can call it. The orphan-org count needs the Forgejo client, which is a package-level singleton, so this function has no receiver.
type StudentOut ¶
type StudentOut struct {
ID uint `json:"id"`
Matrikelnummer *int `json:"matrikelnummer"`
CourseID uint `json:"course_id"`
UserID string `json:"user_id"`
TutorID *uint `json:"tutor_id"`
User *UserBrief `json:"user,omitempty"`
}
StudentOut is the public shape of a course-student row. It mirrors the flat db.Student fields and embeds the preloaded user as a trimmed UserBrief. db.Student.User is tagged json:"-" in the model (repo-wide convention to avoid serialization loops), so the DTO carries the user explicitly and controls exactly which user fields leave the API.
type TaskGetInput ¶
type TaskGetInput struct {
Name string `path:"name"`
}
TaskGetInput holds the request parameters for TaskGet.
type TaskGetOutput ¶
TaskGetOutput holds the response body for TaskGet.
type TaskListInput ¶
type TaskListInput struct{}
TaskListInput holds the request parameters for TaskList (none).
type TaskListOutput ¶
TaskListOutput holds the response body for TaskList.
type TaskRunInput ¶
type TaskRunInput struct {
Name string `path:"name"`
}
TaskRunInput holds the request parameters for TaskRun.
type TaskRunOutput ¶
TaskRunOutput holds the response body for TaskRun.
type TimeSeries ¶
type TimeSeries struct {
Label string `json:"label"`
Points []TimeSeriesPoint `json:"points"`
}
TimeSeries is a named series of time-series points.
type TimeSeriesPoint ¶
TimeSeriesPoint is a single point in a time series.
type TutorOut ¶
type TutorOut struct {
ID uint `json:"id"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CourseID uint `json:"course_id"`
UserID string `json:"user_id"`
User *UserBrief `json:"user,omitempty"`
}
TutorOut is the public shape of a course-tutor row. It mirrors the flat db.Tutor fields and embeds the preloaded user as a trimmed UserBrief. db.Tutor.User is tagged json:"-" in the model (repo-wide convention to avoid serialization loops), so the DTO carries the user explicitly and controls exactly which user fields leave the API.
type UpdateUserBody ¶
type UpdateUserBody struct {
Subject string `json:"subject" required:"false"`
PreferredUsername string `json:"preferred_username" required:"false"`
StudentID string `json:"student_id" required:"false"`
AccountType string `json:"account_type" required:"false"`
Faculty string `json:"faculty" required:"false"`
EnrolledSubject string `json:"enrolled_subject" required:"false"`
Role db.Role `json:"role" required:"false"`
}
UpdateUserBody is the request body for updating a user. name, email, and extra_claims are excluded because the update path never writes them. subject is still accepted so the identity-uniqueness check sees the same values the handler checks, but it is omitted from the update payload.
type UserAdminItem ¶
type UserAdminItem struct {
db.User `json:"user"`
SessionCount int `json:"session_count"`
LastLogin *time.Time `json:"last_login"`
Sessions []SessionBrief `json:"sessions"`
OwnedCourses []CourseBrief `json:"owned_courses"`
TutoredCourses []CourseBrief `json:"tutored_courses"`
EnrolledCourses []CourseBrief `json:"enrolled_courses"`
APIKeys []db.ApiKey `json:"api_keys"`
Grades []RecentGradeItem `json:"grades"`
IsProtectedAdmin bool `json:"is_protected_admin"`
}
UserAdminItem is the full user representation for the admin users page, including session and course relationship data.
func AdminGetUser ¶
func AdminGetUser(gdb *gorm.DB, id string) (UserAdminItem, error)
AdminGetUser fetches a single user with sessions and course relationships for the admin detail modal. Returns the enriched UserAdminItem.
func ScopedGetUser ¶
func ScopedGetUser(gdb *gorm.DB, ownerID, targetUserID string) (UserAdminItem, error)
ScopedGetUser fetches a single user if they are within the caller's scope (self, or a student/tutor in a course the caller owns). Returns gorm.ErrRecordNotFound if the target is out of scope.
type UserBrief ¶
type UserBrief struct {
ID string `json:"id"`
Name string `json:"name"`
PreferredUsername string `json:"preferred_username"`
}
UserBrief is a trimmed user representation that is safe to embed in list endpoints reachable by non-admin staff (e.g. tutors viewing their students). It exposes only identity fields; email, OIDC subject, student ID (matrikelnummer), account type, faculty, enrolled subject, raw extra claims, and the global role are intentionally omitted.
type UserListQuery ¶
type UserListQuery struct {
ID string `query:"id" required:"false" filter:"id"`
Email string `query:"email" required:"false" filter:"email"`
Subject string `query:"subject" required:"false" filter:"subject"`
StudentID string `query:"student_id" required:"false" filter:"student_id"`
Role string `query:"role" required:"false" filter:"role"`
Search string `query:"search" required:"false" search:"name,email"`
SortBy string `query:"sort_by" required:"false" sort:"id,name,email,created_at,updated_at,student_id,role" default_sort:"created_at desc"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
UserListQuery holds the filter and pagination inputs for GET /users. The query/default tags drive huma's request binding; the filter/search/sort tags are ignored by huma and consumed by query.Scopes.
type UsersAdminListInput ¶
type UsersAdminListInput struct {
UsersAdminListQuery
}
UsersAdminListInput holds the request parameters for UsersAdminList.
type UsersAdminListOutput ¶
type UsersAdminListOutput struct {
Body query.PaginatedResponse[UserAdminItem]
}
UsersAdminListOutput holds the response body for UsersAdminList.
type UsersAdminListParams ¶
type UsersAdminListParams struct {
Search string
Role string
Matrikelnummer string
Tutor bool
SortBy string
SortDir string
Page int
PageSize int
}
UsersAdminListParams holds the filter/sort/pagination inputs for the admin users list. Shared by the JSON API handler and the HTML fragment handler.
func ParseUsersAdminListParams ¶
func ParseUsersAdminListParams(c *echo.Context) UsersAdminListParams
ParseUsersAdminListParams extracts UsersAdminListParams from query string. Shared by the JSON API handler, the HTML fragment handler, and the page handler so all three paths agree on how params are read.
type UsersAdminListQuery ¶
type UsersAdminListQuery struct {
Search string `query:"search" required:"false"`
Role string `query:"role" required:"false"`
Matrikelnummer string `query:"matrikelnummer" required:"false"`
Tutor bool `query:"tutor" required:"false"`
SortBy string `query:"sort_by" required:"false"`
SortDir string `query:"sort_dir" required:"false"`
Page int `query:"page" default:"1"`
PageSize int `query:"page_size" default:"25"`
}
UsersAdminListQuery holds the filter/sort/pagination inputs for the admin users list. The query/default tags drive huma's request binding; the values are mapped into UsersAdminListParams for the shared AdminListUsers query path.
type UsersAdminListResult ¶
type UsersAdminListResult struct {
Items []UserAdminItem
Total int64
Page int
PageSize int
TotalPages int
HasNext bool
HasPrev bool
}
UsersAdminListResult holds the paginated result of an admin users list query.
func AdminListUsers ¶
func AdminListUsers(gdb *gorm.DB, p UsersAdminListParams) (UsersAdminListResult, error)
AdminListUsers runs the admin users list query and returns enriched items with pagination metadata. Used by both the JSON API handler and the HTML fragment handler: one query path, two response formats.
func ScopedListUsers ¶
func ScopedListUsers(gdb *gorm.DB, p UsersAdminListParams, ownerID string) (UsersAdminListResult, error)
ScopedListUsers runs the admin users list query but restricts results to users visible to the given staff owner: themselves, plus students and tutors of courses they own. Used by staff-scoped fragment handlers.
type UsersCreateInput ¶
type UsersCreateInput struct {
Body CreateUserBody
}
UsersCreateInput holds the request parameters for UsersCreate.
type UsersCreateOutput ¶
UsersCreateOutput holds the response body for UsersCreate.
type UsersDeleteInput ¶
type UsersDeleteInput struct {
ID string `path:"id"`
}
UsersDeleteInput holds the request parameters for UsersDelete.
type UsersDeleteOutput ¶
type UsersDeleteOutput struct {
Status int
}
UsersDeleteOutput holds the response status for UsersDelete.
type UsersDeleteSessionsInput ¶
type UsersDeleteSessionsInput struct {
ID string `path:"id"`
}
UsersDeleteSessionsInput holds the request parameters for UsersDeleteSessions.
type UsersDeleteSessionsOutput ¶
type UsersDeleteSessionsOutput struct {
Body struct {
DeletedCount int64 `json:"deleted_count"`
}
}
UsersDeleteSessionsOutput holds the response body for UsersDeleteSessions.
type UsersGetInput ¶
type UsersGetInput struct {
ID string `path:"id"`
}
UsersGetInput holds the request parameters for UsersGet.
type UsersGetOutput ¶
UsersGetOutput holds the response body for UsersGet.
type UsersListInput ¶
type UsersListInput struct {
UserListQuery
}
UsersListInput holds the request parameters for UsersList.
type UsersListOutput ¶
type UsersListOutput struct {
Body query.PaginatedResponse[db.User]
}
UsersListOutput holds the response body for UsersList.
type UsersMeCoursesInput ¶
type UsersMeCoursesInput struct{}
UsersMeCoursesInput holds the request parameters for UsersMeCourses (none).
type UsersMeCoursesOutput ¶
type UsersMeCoursesOutput struct {
Body []MyCourseItem
}
UsersMeCoursesOutput holds the response body for UsersMeCourses.
type UsersMeGradesInput ¶
type UsersMeGradesInput struct{}
UsersMeGradesInput holds the request parameters for UsersMeGrades (none).
type UsersMeGradesOutput ¶
type UsersMeGradesOutput struct {
Body []GradeItem
}
UsersMeGradesOutput holds the response body for UsersMeGrades.
type UsersMeInput ¶
type UsersMeInput struct{}
UsersMeInput holds the request parameters for UsersMe (none).
type UsersMeOutput ¶
UsersMeOutput holds the response body for UsersMe.
type UsersMeRecentGradesInput ¶
type UsersMeRecentGradesInput struct{}
UsersMeRecentGradesInput holds the request parameters for UsersMeRecentGrades (none).
type UsersMeRecentGradesOutput ¶
type UsersMeRecentGradesOutput struct {
Body []RecentGradeItem
}
UsersMeRecentGradesOutput holds the response body for UsersMeRecentGrades.
type UsersUpdateInput ¶
type UsersUpdateInput struct {
ID string `path:"id"`
Body UpdateUserBody
}
UsersUpdateInput holds the request parameters for UsersUpdate.
type UsersUpdateOutput ¶
UsersUpdateOutput holds the response body for UsersUpdate.