app

package
v3.24.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: BSD-3-Clause Imports: 23 Imported by: 0

Documentation

Overview

Package app is glabs-web's core: the layer the GraphQL resolvers delegate to, holding the database and enforcing that every request acts only as its own user. Resolvers stay thin — auth gate plus a call into here — so the rules live in one place rather than scattered across the schema.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

func New

func New(database *db.DB, sealer *secrets.Sealer, gitlabHost string) *App

func (*App) Assignment added in v3.4.0

func (a *App) Assignment(ctx context.Context, course, name string) (*AssignmentView, error)

Assignment returns the source values and resolved preview for one assignment of one of the caller's own courses. It returns nil (no error) when the course exists but has no assignment by that name; ErrCourseNotFound propagates when the course itself is not the caller's.

func (*App) AssignmentReport added in v3.16.0

func (a *App) AssignmentReport(ctx context.Context, course, name string) (*report.Reports, error)

AssignmentReport fetches a live report over the repositories of one assignment of one of the caller's courses, using the caller's stored GitLab token. It returns nil (no error) when there is no such assignment or it cannot be resolved (e.g. an abstract base); it errors when no token is stored or GitLab is unreachable.

func (*App) AssignmentURLs added in v3.15.0

func (a *App) AssignmentURLs(ctx context.Context, course, name string) (*AssignmentURLs, error)

AssignmentURLs returns the repository URLs for one assignment of one of the caller's own courses. It returns nil (no error) when the course has no such assignment, or when the assignment cannot be resolved (e.g. an abstract base) — in both cases there simply are no URLs. ErrCourseNotFound propagates when the course itself is not the caller's.

func (*App) CheckCourse added in v3.19.0

func (a *App) CheckCourse(ctx context.Context, courseName string) (*gitlab.CheckResult, error)

CheckCourse resolves the course roster against GitLab (one-shot, no progress), using the caller's stored token.

func (*App) CopyAssignment added in v3.23.0

func (a *App) CopyAssignment(ctx context.Context, course, from, newName string) (*AssignmentView, error)

CopyAssignment duplicates one of the caller's assignments under a new name. Only the name has to be unique — the copy is otherwise identical to the source, including its `extends`. It validates the new name (it becomes a GitLab path segment), rejects a name that already exists, then persists — re-marshalling the whole course YAML. The persisted round-trip (encode → store → decode) makes the copy fully independent of the source.

func (*App) Course added in v3.2.0

func (a *App) Course(ctx context.Context, name string) (*db.StoredCourse, error)

Course returns one of the caller's own courses.

func (*App) CourseLint added in v3.2.0

func (a *App) CourseLint(ctx context.Context, name string) ([]config.Finding, error)

CourseLint returns the lint findings for one of the caller's own courses.

func (*App) CourseYAML added in v3.2.0

func (a *App) CourseYAML(ctx context.Context, name string) ([]byte, error)

CourseYAML returns the course as a downloadable YAML file: the original bytes if they are still current, otherwise a re-encoding of the stored source.

func (*App) Courses added in v3.2.0

func (a *App) Courses(ctx context.Context) ([]*db.StoredCourse, error)

Courses returns the caller's own courses.

func (*App) CreateCourse added in v3.9.0

func (a *App) CreateCourse(ctx context.Context, name, coursePath, semesterPath string, useCoursenameAsPrefix, useEmailDomainAsSuffix bool) (*db.StoredCourse, error)

CreateCourse creates a new, empty course from scratch for the caller. It fails if the caller already has a course by that name — assignments are added afterwards with SetAssignment.

func (*App) DeleteAssignment added in v3.9.0

func (a *App) DeleteAssignment(ctx context.Context, course, name string) (bool, error)

DeleteAssignment removes one assignment from one of the caller's courses and re-marshals the course YAML. It returns false when there was no such assignment (and does not touch the course).

func (*App) DeleteCourse added in v3.2.0

func (a *App) DeleteCourse(ctx context.Context, name string) error

DeleteCourse removes one of the caller's own courses.

func (*App) GetUserByEmail

func (a *App) GetUserByEmail(ctx context.Context, email string) (*model.User, error)

GetUserByEmail looks up a user for the auth middleware's allowlist check.

func (*App) GitLabTokenStatus added in v3.3.0

func (a *App) GitLabTokenStatus(ctx context.Context) (*GitLabTokenStatus, error)

GitLabTokenStatus reports whether the caller has a stored token, without decrypting or returning it.

func (*App) ImportAssignmentYAML added in v3.17.0

func (a *App) ImportAssignmentYAML(ctx context.Context, course, assignmentYAML string) (*AssignmentView, error)

ImportAssignmentYAML upserts a single assignment into one of the caller's courses from a YAML snippet in the same keyed form it has in a course file:

blatt3:
  per: student
  accesslevel: developer
  startercode:
    url: git@gitlab.lrz.de:...

The snippet's single top-level key is the assignment name. The block is merged into the stored course, decoded and validated through the same resolver the editor uses (a concrete assignment that does not resolve is rejected), then persisted — re-marshalling the course YAML, exactly like SetAssignment.

func (*App) ImportCourseYAML added in v3.2.0

func (a *App) ImportCourseYAML(ctx context.Context, yaml string) (*db.StoredCourse, error)

ImportCourseYAML parses an uploaded course file and stores it for the caller, keeping the original bytes so a later download returns exactly what was uploaded. Importing a course whose name already exists replaces it.

An inline seeder signKey is rejected: it is a private key, and storing it would mean sealing it, hiding it in GraphQL, and excluding it from dumps — four leaks for a feature no course file uses. signKeyFile (a path) is fine.

func (*App) LocalDevUser

func (a *App) LocalDevUser() *model.User

LocalDevUser is the identity used when auth is disabled (local development). It is never consulted when auth is enabled.

func (*App) PlanOp added in v3.20.0

func (a *App) PlanOp(ctx context.Context, op, course, assignment string, params map[string]string, onlyFor []string) (*OpPlan, error)

PlanOp resolves an assignment and returns the plan for a mutating operation — which repositories it would touch and any warnings — plus a confirm token. It does NOT touch GitLab; it is a pure, token-free preview. A missing/unresolvable assignment or an unknown op is an error.

func (*App) RemoveGitLabToken added in v3.3.0

func (a *App) RemoveGitLabToken(ctx context.Context) (*GitLabTokenStatus, error)

RemoveGitLabToken deletes the caller's stored GitLab PAT.

func (*App) RenameAssignment added in v3.24.0

func (a *App) RenameAssignment(ctx context.Context, course, oldName, newName string) (*AssignmentView, error)

RenameAssignment renames one of the caller's assignments within a course and re-marshals the course YAML. Any sibling that inherits from the old name via `extends` is repointed to the new name (so, unlike editing plain YAML by hand, no inheritance chain silently breaks). It fails if the new name is not path-safe or already exists.

func (*App) RenameCourse added in v3.24.0

func (a *App) RenameCourse(ctx context.Context, oldName, newName string) (*db.StoredCourse, error)

RenameCourse renames one of the caller's own courses. The course name is the YAML file's top-level key, so the raw bytes are re-encoded under the new name. It fails if the new name is not path-safe or the caller already has a course by that name. Assignments, students and groups are carried over unchanged.

func (*App) RunOp added in v3.21.0

func (a *App) RunOp(ctx context.Context, token, confirmPhrase string) (<-chan RunLine, error)

RunOp validates a plan token and runs the mutating GitLab operation it describes, streaming its output line by line. The pre-flight checks (token, config drift, seeder, confirm phrase, exclusive lock, GitLab token) fail synchronously with an error; once the operation starts, failures are streamed as an ERROR line.

The operation runs on a context DETACHED from the subscription (context.WithoutCancel): closing the browser tab cancels the subscription (so the reporter stops streaming) but the operation keeps running to completion.

func (*App) ServerInfo

func (a *App) ServerInfo() *model.ServerInfo

ServerInfo returns the build metadata main stashed in viper (ldflags at release, VCS info otherwise), so the GUI can show which build is running.

func (*App) SetAssignment added in v3.6.0

func (a *App) SetAssignment(ctx context.Context, course, name string, draft map[string]string) (*AssignmentView, error)

SetAssignment applies a draft to one of the caller's assignments: it validates, rejects a concrete draft that does not resolve, then persists — re-marshalling the whole course YAML (a real edit gives up the verbatim original bytes).

func (*App) SetCourse added in v3.10.0

func (a *App) SetCourse(ctx context.Context, name, coursePath, semesterPath string, useCoursenameAsPrefix, useEmailDomainAsSuffix bool) (*db.StoredCourse, error)

SetCourse updates the course-level settings of one of the caller's courses, leaving assignments, students and groups untouched, and re-marshals the course YAML.

func (*App) SetCourseGroups added in v3.12.0

func (a *App) SetCourseGroups(ctx context.Context, name string, groups map[string][]string) (*db.StoredCourse, error)

SetCourseGroups replaces the course-level groups of one of the caller's courses. Groups with a blank name or no members after cleaning are dropped.

func (*App) SetCourseStudents added in v3.12.0

func (a *App) SetCourseStudents(ctx context.Context, name string, students []string) (*db.StoredCourse, error)

SetCourseStudents replaces the course-level students of one of the caller's courses (the GUI merges additively before calling this).

func (*App) SetGitLabToken added in v3.3.0

func (a *App) SetGitLabToken(ctx context.Context, token string) (*GitLabTokenStatus, error)

SetGitLabToken stores the caller's GitLab PAT, AES-256-GCM encrypted. Write-only: the token is never returned by any query, and the plaintext is never persisted or logged. Fails closed if no secrets.key is configured.

func (*App) StreamAssignmentReport added in v3.18.0

func (a *App) StreamAssignmentReport(ctx context.Context, course, name string) (<-chan ReportEvent, error)

StreamAssignmentReport generates the report for one assignment and streams the GitLab client's progress as it goes, ending with exactly one done event that carries the finished report (or an error). The returned channel is closed when generation finishes or ctx is cancelled.

Like AssignmentReport, a missing or unresolvable assignment yields a done event with a nil report (no error); a missing token or an unreachable GitLab yields a done event whose Error is set — surfaced to the client rather than tearing down the subscription.

func (*App) StreamCheckCourse added in v3.19.0

func (a *App) StreamCheckCourse(ctx context.Context, courseName string) (<-chan CheckEvent, error)

StreamCheckCourse checks the course roster against GitLab and streams progress per student, ending with one done event carrying the result. A missing token or an unreachable GitLab yields a done event whose Error is set.

func (*App) ValidateAssignmentDraft added in v3.6.0

func (a *App) ValidateAssignmentDraft(ctx context.Context, course, name string, draft map[string]string) (*ValidationResult, error)

ValidateAssignmentDraft validates a draft against the real resolver without saving.

type AssignmentURLs added in v3.15.0

type AssignmentURLs struct {
	// Per is "student" or "group".
	Per string
	// GroupURL is the assignment-level group URL where all the repos live.
	GroupURL string
	// Repos is one URL per student/group repository.
	Repos []config.RepoURL
}

AssignmentURLs are the repository URLs for one assignment: the assignment-level group URL plus one entry per student or per group. Derived purely from the resolved configuration — no GitLab token or API call is involved.

type AssignmentView added in v3.4.0

type AssignmentView struct {
	Course   string
	Name     string
	Extends  string
	Abstract bool
	// ExtendsOptions lists the names of the sibling assignments this one may
	// inherit from (all assignments in the same course except this one, sorted).
	// `extends` is course-internal, so these are exactly the valid choices for
	// the editor's dropdown.
	ExtendsOptions []string
	// Own holds the assignment's own (source) field values, keyed by
	// FieldMeta.key, for pre-filling the editor form.
	Own []FieldValue
	// Resolved is the Show() rendering (may contain ANSI). Empty when the
	// assignment cannot be resolved (then ResolveError explains why).
	Resolved string
	// ResolveError is set when resolution fails — e.g. an abstract base, a
	// missing parent, or an `extends` cycle. Not a fault: an abstract base is a
	// valid document that simply has no resolved form.
	ResolveError string
}

AssignmentView is one assignment in source (own) form plus its resolved preview — the same rendering `glabs show` produces. It makes the inheritance visible in the browser exactly as the CLI's confirmation gate does.

type CheckEvent added in v3.19.0

type CheckEvent struct {
	Message string
	Done    bool
	Result  *gitlab.CheckResult
	Error   string
}

CheckEvent is one item in the course-check stream: a progress message while the roster is checked, or the single final done event carrying the result (or an error, e.g. no token stored).

type FieldKind added in v3.4.0

type FieldKind string

FieldKind is the input shape the GUI should render for a field.

const (
	KindString     FieldKind = "STRING"
	KindBool       FieldKind = "BOOL"
	KindEnum       FieldKind = "ENUM"
	KindInt        FieldKind = "INT"
	KindStringList FieldKind = "STRINGLIST"
)

type FieldMeta added in v3.4.0

type FieldMeta struct {
	Key         string
	Label       string
	Description string
	// Group is the section the field belongs to ("" for the top-level group,
	// e.g. "Startercode" for the startercode block), so the GUI can render
	// grouped sections. Nested keys are dotted, e.g. "startercode.url".
	Group      string
	Kind       FieldKind
	Required   bool
	Deprecated bool
	Example    string
	Options    []FieldOption
}

FieldMeta describes one editable assignment field.

func AssignmentApprovalRuleSchema added in v3.14.0

func AssignmentApprovalRuleSchema() []FieldMeta

AssignmentApprovalRuleSchema returns the metadata for one approval rule — a row of the repeat-group `approvals.rules` list.

func AssignmentApprovalSettingsSchema added in v3.14.0

func AssignmentApprovalSettingsSchema() []FieldMeta

AssignmentApprovalSettingsSchema returns the metadata for the mergeRequest approval settings. These are tri-state: an ENUM whose empty option means "not set" (inherit), so `an`/`aus` map to *bool true/false and "" to nil.

func AssignmentBranchSchema added in v3.13.0

func AssignmentBranchSchema() []FieldMeta

AssignmentBranchSchema returns the metadata for one branch rule — a row of the repeat-group `branches` list. The GUI renders one such control set per row.

func AssignmentSchema added in v3.4.0

func AssignmentSchema() []FieldMeta

AssignmentSchema returns the metadata for the assignment editor's fields.

type FieldOption added in v3.4.0

type FieldOption struct {
	Value       string
	Label       string
	Description string
}

FieldOption is one choice of an ENUM field — a dropdown entry with its own short description.

type FieldValue added in v3.5.0

type FieldValue struct {
	Key   string
	Value string
}

FieldValue is one field's own (source) value, stringified and keyed by the same key as FieldMeta so the GUI can pre-fill the schema-driven form.

type GitLabTokenStatus added in v3.3.0

type GitLabTokenStatus struct {
	Set       bool
	UpdatedAt *time.Time
}

GitLabTokenStatus reports whether the caller has stored a GitLab token and when — never the token itself.

type OpPlan added in v3.20.0

type OpPlan struct {
	Op            string
	Course        string
	Assignment    string
	Resolved      string
	Targets       []PlannedTarget
	Warnings      []string
	Destructive   bool
	ConfirmPhrase string
	Token         string
	ExpiresAt     time.Time
}

OpPlan is the preview of a mutating operation before it runs: the resolved config, the repositories it would touch, warnings, and an opaque confirm token carrying a hash of the resolved config — so a later runOp can reject a plan whose config changed underneath it (strictly stronger than the CLI's Scanln gate).

type PlannedTarget added in v3.20.0

type PlannedTarget struct {
	For  string
	Repo string
	URL  string
}

PlannedTarget is one repository an operation would touch.

type ReportEvent added in v3.18.0

type ReportEvent struct {
	Message string
	Done    bool
	Report  *report.Reports
	Error   string
}

ReportEvent is one item in the assignment-report stream: either a progress message while the report is being fetched, or the single final event carrying the finished report (or an error).

type RunLine added in v3.21.0

type RunLine struct {
	Level string
	Text  string
}

RunLine is one line of an operation's streamed output: a level (INFO, WARN, ERROR, PROGRESS, RESULT, DONE) plus text (may contain ANSI, though the reporter strips it).

type ValidationResult added in v3.6.0

type ValidationResult struct {
	OK           bool
	Errors       []string
	Resolved     string
	ResolveError string
}

ValidationResult reports whether a draft assignment is saveable and — when it resolves — its preview.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL