Documentation
¶
Overview ¶
Package formlookup serves a task form's remote data sources: a person types into a directory field and sees the first matching entries of a directory the server never copies (ADR-0473).
The form says what may be searched; this package enforces what the person may access; the Worker performs the search; the browser holds one page; and the durable workflow records only the value the person finally submits.
**What the request may say** is what a person can know: the term they typed, what they picked in the form's other fields, a cursor this server handed them, and a page size no larger than the field's. Which Worker, which tenant, which resource, which properties are searched and returned — all of that is read from the task's stored form and from the provider registry, and a request naming any of it is refused.
**This area owns no state**, like formgen: its collaborators are the server's and each observes the single writer itself (I3). What it does hold — a query waiting for a Worker Instance — waits on the request's own goroutine, with the run loop free, and is never written anywhere: nothing here reaches the log, the processor or recovery.
Index ¶
Constants ¶
const ( // VerifyLookup looks the value up once more, under the field's filters. VerifyLookup = "lookup" // VerifyFormat checks only that the value has the shape of one. VerifyFormat = "format" )
The ways a submitted value is checked before its task completes.
const DataSourceMember = "atlasDataSource"
DataSourceMember is the component member that makes a select a directory field.
const DefaultTimeout = 8 * time.Second
DefaultTimeout is what a person waits for at most. Graph answers a filtered page in well under a second; a lookup still waiting after this is not going to be useful.
const Version = 1
Version is the one version of the block this server reads. A form written for a newer one is refused at save with that reason, rather than half-understood.
Variables ¶
var ( ErrNoTask = errors.New("formlookup: no open task with that key") ErrForbidden = errors.New("formlookup: the caller may not work on this task") )
The task collaborator's two refusals.
var Codes = []string{
"forbidden", "not_found", "invalid_query", "invalid_cursor", "invalid_configuration",
"rate_limited", "worker_unavailable", "worker_busy", "provider_throttled",
"provider_unavailable", "provider_refused", "timeout",
}
Codes are the machine-readable codes a lookup or a refused completion answers with, beside the human-readable error. A client branches on these and words them itself; the console's catalogue carries a message for each (remote.error.<code>), which a test holds it to.
Functions ¶
Types ¶
type Config ¶
type Config struct {
// Task authorizes the caller against a task — the question task completion asks,
// ADR-0317 — and returns its form. ErrNoTask and ErrForbidden are its refusals.
Task func(r *http.Request, key uint64) (Task, error)
// Worker resolves a Worker by name from the Worker store.
Worker func(name string) (Worker, bool, error)
// Workers lists the Workers a model author may pick, for the editor.
Workers func(r *http.Request) ([]Worker, error)
// Ask puts a query to a Worker Instance and waits for its answer.
Ask func(ctx context.Context, jobType, connector string, q lookup.Query, timeout time.Duration) (lookup.Page, error)
// Allow is the per-person rate limit.
Allow func(key string) bool
// Principal names the caller, for the rate limit and for the cursor a page is
// continued with. Empty when the server runs without authentication.
Principal func(r *http.Request) string
// Timeout bounds one query.
Timeout time.Duration
// MaxBody bounds a request's body: the server's Request budget.
MaxBody int64
}
Config is the server's half of this area.
type Field ¶
type Field struct {
Key string
Label string
Required bool
// Conditional is set when form-js may hide the field. The server cannot evaluate
// form-js's condition, so it does not insist on a value a hidden field never sends.
Conditional bool
// Disabled fields are not submitted by form-js, and not checked.
Disabled bool
Source Source
Provider Provider
}
Field is one directory field of a form, checked.
func (Field) ActiveOnly ¶
ActiveOnly reports whether disabled records are left out.
func (Field) DescriptionProperty ¶
DescriptionProperty is what the line under an option's label reads.
func (Field) LabelProperty ¶
LabelProperty is what an option's label reads.
func (Field) MinSearchLength ¶
MinSearchLength is how many characters a term needs.
func (Field) Properties ¶
Properties are everything a lookup for this field reads, and nothing more: the value, what the option shows, and the fallback for a record that leaves either empty.
func (Field) SearchFields ¶
SearchFields are the properties a term is a prefix of.
type Filter ¶
type Filter struct {
Property string `json:"property"`
Field string `json:"field,omitempty"`
Value string `json:"value,omitempty"`
// Required makes a bound filter a precondition: no search runs until its field has
// a value. Without it, an empty field leaves the search unnarrowed.
Required bool `json:"required,omitempty"`
}
Filter narrows a search by equality. Field binds it to the value another field of the same form holds; Value fixes it, whatever a request says.
type Form ¶
type Form struct {
Fields []Field
// contains filtered or unexported fields
}
Form is what a schema says about its directory fields and about the fields they may be bound to.
func Parse ¶
Parse reads a form-js schema's directory fields and checks every one of them against what this server can honour. A schema without any is every form that existed before them and parses to none; a malformed atlasDataSource is refused with the field and the reason.
type Item ¶
type Item struct {
// Value is what the form submits: the record's identifier.
Value string `json:"value"`
// Label is what a person reads; Description the line under it.
Label string `json:"label"`
Description string `json:"description,omitempty"`
Details map[string]string `json:"details,omitempty"`
}
Item is one option as the form shows it.
type Option ¶
type Option struct {
Label string `json:"label,omitempty"`
Description string `json:"description,omitempty"`
Details []string `json:"details,omitempty"`
}
Option says what a result shows: the label a person reads, the line under it, and up to four details beside it. The value is always the source's own identifier.
type Provider ¶
type Provider struct {
// WorkerType is the Worker Type a form's Worker must be of — the kind of its
// Console record ("entra").
WorkerType string `json:"workerType"`
// Resource is what is searched, in the Worker Type's vocabulary ("users").
Resource string `json:"resource"`
// JobType routes the query: it reaches Worker Instances serving this job type.
JobType string `json:"-"`
// Label names the source to a model author.
Label string `json:"label"`
// ValueProperty identifies a record; it is what a form submits.
ValueProperty string `json:"valueProperty"`
Searchable []string `json:"searchable"`
Filterable []string `json:"filterable"`
Readable []string `json:"readable"`
// DefaultLabel and DefaultDescription are what an option shows when the form
// names nothing; Fallback stands in for either when a record leaves it empty — a
// user without a mailbox still has a user principal name.
DefaultLabel string `json:"defaultLabel"`
DefaultDescription string `json:"defaultDescription"`
Fallback string `json:"fallback,omitempty"`
// ValueFormat says in words what a value looks like, for an error message.
ValueFormat string `json:"valueFormat"`
// contains filtered or unexported fields
}
Provider is one remote data source a form may name: a resource of a Worker Type, what of it may be searched, filtered and shown, and how its records are told apart.
It is the server's half of a rule the Worker Type keeps too. The lists come from the Worker Type's own table (for Entra, entra.LookupResources), so the server refuses at save and at query time exactly what the Worker would refuse at answer time, and the two cannot drift: there is one table, and this is a view of it.
func ProviderFor ¶
ProviderFor finds the source a form names.
func Providers ¶
func Providers() []Provider
Providers lists the remote data sources this server offers.
func (Provider) ValidValue ¶
ValidValue reports whether v has the shape of a value of this source.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service serves remote data sources. Build it with New.
func (*Service) CheckSubmission ¶
func (s *Service) CheckSubmission(ctx context.Context, schema []byte, vars map[string]any) *SubmissionError
CheckSubmission checks every directory field of schema against the variables a completion submits, in the order the form shows them, and returns the first refusal. A form without a directory field is not checked at all, so every form that existed before them completes exactly as it did.
func (*Service) HandleQuery ¶
func (s *Service) HandleQuery(w http.ResponseWriter, r *http.Request)
HandleQuery is POST /api/v1/tasks/{key}/form-data/{field}/query.
func (*Service) HandleSources ¶
func (s *Service) HandleSources(w http.ResponseWriter, r *http.Request)
HandleSources is GET /api/v1/form-data/sources: what a model author can configure — the sources this server offers, and the Workers a field can name, each saying whether it lets forms search it.
type Source ¶
type Source struct {
Version int `json:"version"`
WorkerType string `json:"workerType"`
Worker string `json:"worker"`
Resource string `json:"resource"`
SearchFields []string `json:"searchFields,omitempty"`
Filters []Filter `json:"filters,omitempty"`
Option Option `json:"option,omitempty"`
PageSize int `json:"pageSize,omitempty"`
// MinSearchLength is how many characters a term needs before it is searched; 0
// lists what the filters admit without one. Absent means 2.
MinSearchLength *int `json:"minSearchLength,omitempty"`
// ActiveOnly leaves disabled accounts out. Absent means true: a person picked for
// a process is normally somebody who can still sign in, and a leaver process that
// wants the disabled ones says so.
ActiveOnly *bool `json:"activeOnly,omitempty"`
Verify string `json:"verify,omitempty"`
}
Source is the atlasDataSource block as a form states it.
type SubmissionError ¶
SubmissionError is a completion refused for a directory field's value.
func (*SubmissionError) Error ¶
func (e *SubmissionError) Error() string
func (*SubmissionError) Write ¶
func (e *SubmissionError) Write(w http.ResponseWriter)
Write answers the refused completion in the lookup's error shape.
type Task ¶
type Task struct {
Schema []byte
}
Task is what a lookup needs of the task it is made from: its form, as the form store holds it now.
type Worker ¶
type Worker struct {
Name string `json:"name"`
WorkerType string `json:"workerType"`
Enabled bool `json:"enabled"`
// FormLookups is the Worker's own switch: its editors decide whether a form may
// search through its credential (ADR-0205). Seeing a form, or editing one, is not
// that permission.
FormLookups bool `json:"formLookups"`
}
Worker is a configured Worker as this area judges it. No endpoint and nowhere to put a credential.