Help us shape the future of Go! Take the 2026 Go Developer Survey

registrations

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 30 Imported by: 0

README

Registrations

Sign-ups for events or other subjects: places, prices and a deadline, a confirmation e-mail with a personal code, and a page where visitors look up or cancel their registration.

An instance is usually linked to an Events instance, so editors open registration per event. Without that link, editors add their own subjects, such as a course, by ID. The module takes no payments: it shows the editors' payment link, and editors mark registrations as paid.

Add it to the site

app.Use(
    events.Module("agenda", "Agenda"),
    registrations.Module("signup", "Sign-ups", registrations.ForEvents("agenda")),
)

The key (signup) is used in the admin, in form actions and in the template functions, and must be unique on the site. The title (Sign-ups) is what editors see in the admin and the page editor.

  • ForEvents("agenda") links the instance to that Events instance. Editors pick its events in the admin, e-mail names the event and when it takes place, and registration closes when the event starts unless editors set a deadline. Add the Events instance as well.
  • Currency("GBP") sets the currency of the prices; the default is EUR. It must be an ISO 4217 code, or the app does not start.

Without ForEvents, editors add subjects in the admin with an ID (letters, digits, -, _, . and :, up to 64 characters) and a name. Templates pass that ID wherever they would pass an event's .ID.

With ForEvents, an event's page also tells search engines about its registration. The Events module gives the page a schema.org Event in its structured data, which core's head tags write with {{structuredData}}, and this module adds an Offer to it as offers: the price per adult, such as "12.50", or "0.00" when it is free, the currency, the event's page as url, InStock while visitors can register or SoldOut when every place is taken, and as validThrough the time registration closes, the event's start unless editors set a deadline. An event without registration settings, and registration that is switched off or past its deadline while places are left, give no offer. See Search and SEO.

Show the sign-up form

The registrationForm component renders the sign-up box of one subject. On an event page (agenda/event.gohtml or events/event.gohtml):

{{registrationForm "signup" .ID}}

It shows the prices, the places left, the deadline, the result of the visitor's last post and the form, or a notice when the subject is full or closed. When the instance is placed on a page, it also links to the lookup page. A subject without registration settings renders nothing, so the line can stay in the template of every event.

A theme changes the markup with signup/form.gohtml for this instance, or registrations/form.gohtml for every instance. Generate the default to start from, together with the other templates and e-mails of the instance:

task templates -- signup

The default uses wt-registration classes with the shared wt-form, wt-notice and wt-button, laid out by the optional stylesheet webthings.css, which the layout links with {{styles "webthings.css" "site.css"}} (see The base stylesheet). Its texts go through tl, so the site's translations apply.

To write the form in the template itself, registration returns the subject's availability in the page's language:

{{with registration "signup" .ID}}
    <section id="signup">
        {{with .Notes}}<div class="notes">{{.}}</div>{{end}}
        {{if .Open}}
            {{form_open .Form}}
                {{form_field .Form "subject" nil}}
                {{form_field .Form "name" nil}}
                {{form_field .Form "email" nil}}
                {{form_field .Form "adults" nil}}
                {{if .AllowChildren}}{{form_field .Form "children" nil}}{{end}}
                {{form_field .Form "notes" nil}}
                <button>Sign up</button>
            {{form_close}}
            {{if .Capacity}}<p>{{.Left}} places left</p>{{end}}
        {{else if .Full}}<p>This event is full.</p>
        {{else if .Configured}}<p>Registration is closed.</p>{{end}}
    </section>
{{end}}

Configured is set once editors saved settings for the subject. Open is set while registration is switched on, the deadline has not passed and places are left. Prices are amounts in cents: {{money .Prices.Adult .Currency}} shows them in the page's language. Notes are the editors' notes for registrants, rendered from Markdown with their own paragraphs, so they go in a <div> rather than a <p>.

.Form is the sign-up form: form_open writes the form tag, posting to .Action, with the spam trap and the page to return to, the element whose id is the instance key. form_field renders one of its fields by its key, with its label and limits, translated with the site's translations and in the site's form theme; the ids start with the key, such as signup-name. subject is a hidden field with the subject's ID, adults start at 1, and while places are limited adults and children each go up to .Left, at most 50. See Template functions. Inputs written by hand with the field names work too.

Visitors

The form posts to /_/signup/register (.Action, or {{registerURL "signup"}} anywhere) with the fields of registrations.SignupInput, plus the spam trap and the page to return to that form_open adds.

Field
subject the subject ID, such as the event's .ID (required)
name, email required; the name on one line
adults 1 when missing or empty
children 0 when missing; refused unless editors allow children
notes optional remarks, up to 2000 characters

One sign-up takes at most 50 places, and sign-ups that arrive at the same moment never exceed the capacity. The registration keeps the language of the page the form was on.

After signing up, the visitor gets a confirmation e-mail with a code such as K7Q4-9M2X. When the instance is placed on a page, the visitor then lands on the registration's own page with ?signup=registered; otherwise back on the form's page with ?signup=registered&code=K7Q4-9M2X. Other results return to the form's page:

?signup= Meaning
full not enough places left
closed registration is not open
invalid a field is missing or wrong, such as a number of places that is not a number
throttled too many posts: a visitor may send 10 sign-ups or cancellations per 10 minutes

With invalid or full, the form shows the visitor's answers again, with a message in the page's language at each field to correct. The component and form_field do this without a change to the template; inputs written by hand do not. Of several sign-up forms on one page, only the one for the subject the visitor chose shows them. See A post with mistakes. A sign-up or cancellation that fails for another reason, such as an unreachable database, gets the site's error page, 500.gohtml.

{{registrationResult "signup"}} reads the result and {{registrationCode "signup"}} the code; the component shows both. Posts that fill in the spam trap are answered with registered and stored nowhere. Visitors are told apart by IP address, so list a reverse proxy in Config.TrustedProxies. A post that stores nothing, spam, invalid, full, closed or throttled, leaves the pages in the site's output cache as they are; see Modules and the output cache.

The registration page

Place the instance on a page to let visitors look up and cancel their registration. With the page at /en/registration:

Address Template Shows
/en/registration signup/lookup.gohtml a form asking for the code
/en/registration/<code> signup/registration.gohtml one registration with its cancel form

registrations/<name>.gohtml serves every instance without a design of its own. The lookup page gets a registrations.LookupView. Its .Form is the form of registrations.LookupInput, sent to .Action with method GET as ?code=, with the code field's id registration-code:

{{/* @dot github.com/donseba/go-webthings/modules/registrations.LookupView */}}
<h1>{{.Title}}</h1>
{{if .NotFound}}<p>No registration has the code {{.Code}}.</p>{{end}}

{{form_open .Form}}
    {{form_field .Form "code" nil}}
    <button>Look up</button>
{{form_close}}

A code typed in lowercase, with spaces or without the dash lands on the right address. Every answer below the page, "not found" for an unknown code included, is sent with Cache-Control: private, no-store and X-Robots-Tag: noindex, so neither Stats nor the missed paths of Redirects record a code. Cancelling needs the code and the e-mail address used to sign up, the fields of registrations.CancelInput:

{{/* @dot github.com/donseba/go-webthings/modules/registrations.RegistrationView */}}
<h1>{{.Subject.Title}}</h1>
<p>{{.Code}} · {{.Name}} · {{.Adults}} adults{{if .Total}} · {{money .Total .Currency}}{{end}}</p>
{{with .PaymentLink}}<p>Please pay using: {{.}}</p>{{end}}
{{with .Info}}<div class="notes">{{.}}</div>{{end}}

<section id="{{.Key}}">
    {{if eq .Result "cancelled"}}<p>Your registration is cancelled.</p>{{end}}
    {{if eq .Result "invalid"}}<p>That e-mail address does not match this registration.</p>{{end}}
    {{if not .Cancelled}}
        {{form_open .Form}}
            {{form_field .Form "code" nil}}
            {{form_field .Form "email" nil}}
            <button>Cancel registration</button>
        {{form_close}}
    {{end}}
</section>

Here .Notes are the visitor's own remarks, as plain text, and .Info the editors' notes for registrants, rendered from Markdown. .Subject.When is when the event takes place, a frontend.When as an event's .When gives it, so the partial of the Events README shows it too; it is zero for a subject that is no event (.Subject.When.IsZero). The starting point from task templates -- signup shows it as that partial does: an event over several days with a time as "date, time – date, time", such as "Monday 16 November 2026, 09:00 – Tuesday 17 November 2026, 18:00". .Form is the cancel form, with the code as a hidden field; it returns the visitor to the element whose id is .Key, the instance key. After invalid, it shows the address the visitor typed again, as the sign-up form does.

Cancelling frees the places and sends a cancellation e-mail. An unpaid registration gets the payment status cancelled; a paid one stays paid, so it can be refunded.

In the admin

Each instance has its own section (/admin/signup; /admin is the default admin path). The overview lists the subjects with their status (open, closed or full), registrations and places taken. With ForEvents it lists every event of the agenda; without it, New subject adds one.

A subject's Settings hold:

  • Open for registration, the number of Places (adults and children together; 0 is unlimited) and Registration closes, in the site's timezone.
  • Price per adult and, when Children can be registered, Price per child, typed as 12.50 or 12,50.
  • Per language, the Notes for registrants in Markdown, shown with the form, on the registration page and in the confirmation, and a Payment link (a payment URL or bank details), shown while payment is pending.

The subject's page lists its registrations, cancelled ones included, with the totals and Export CSV. A registration with a total starts as pending. Editors change its payment status, add admin notes, cancel it or move it to the trash; cancelling in the admin sends no e-mail. Move to trash moves a registration to the trash and frees its places; a restored registration keeps its code, and restoring is refused when too few places are left by then. Editors' rights are set per instance in the groups' permission matrix; Export CSV needs the export right (see Groups and the matrix). In the export, a value that starts with =, +, - or @ gets a leading apostrophe, so a spreadsheet shows it as text instead of running it as a formula.

E-mail

Two mail templates, sent to the visitor in the language of the page they signed up on:

  • confirmation, after signing up: the code, the event's date and time, the places, the total, the payment link, the notes for registrants as the Markdown editors wrote (.Info), and a link to the registration page when the instance is on a page.
  • cancellation, after cancelling on the site.

The confirmation shows when the event takes place as the starting point of the registration page does, so an event over several days with a time as "date, time – date, time". Replies go to the site's e-mail address from Site settings. A theme replaces the texts with mail/signup/<name>.gohtml or mail/registrations/<name>.gohtml. A mail that cannot be sent is logged; the registration stands.

From Go

registrations.Of(app, "signup") returns the instance once the app has started, for example to open registration for an event from seed data:

signup := registrations.Of(app, "signup")

err := signup.SaveSettings(ctx, registrations.Settings{
    SubjectID:  eventID,
    Open:       true,
    Capacity:   40,
    AdultPrice: 1250, // 12.50
    Texts:      []registrations.SubjectText{{Locale: "en", Notes: "Doors open at **19:30**."}},
})

Notes are Markdown, as editors write them in the admin.

Availability, Registrations and Summaries read the sign-ups, and ByCode finds one by its code. Register signs someone up with the same checks as the form, but sends no e-mail, and Cancel cancels a registration, freeing its places. Delete, Undelete and Purge move a registration to the trash, bring it back or remove it for good. What SaveSettings, Register, Cancel, Delete and Undelete change, such as the places left, shows on the site at once, also on pages in the site's output cache; see Modules and the output cache.

  • Events holds the events visitors sign up for.
  • Forms collects other questions from visitors, with an inbox.

Documentation

Overview

Package registrations lets visitors sign up for events, or for any other subject: places with an optional capacity, adults and children with prices, a deadline, a confirmation e-mail with a personal code, and a page where visitors look up and cancel their registration. Editors open registration per subject, follow sign-ups and payments, and export them as CSV.

Link an instance to an events instance so editors pick events in the admin, and registration closes when an event starts:

app.Use(
	events.Module("agenda", "Agenda"),
	registrations.Module("signup", "Sign-ups", registrations.ForEvents("agenda")),
)

Without ForEvents, editors add subjects by ID (any text up to 64 characters, such as a page or product ID) and name.

Registering

The sign-up form can sit on any page, typically events/event.gohtml. It posts to the module's action (registerURL) with these fields (SignupInput):

subject   the subject ID, for example the event's .ID (required)
name      the visitor's name (required)
email     the visitor's e-mail address (required)
adults    number of adults, at least 1; 1 when the field is missing
children  number of children; 0 when missing, only when allowed
notes     optional remarks for the organiser

Availability.Form is its model for go-form's functions, with the adults and children at most the places left; form_open adds the spam trap and the return address, the element with the instance key as its id. A minimal form:

{{with registration "signup" .ID}}
  <div id="signup">
    {{if .Open}}
      {{form_open .Form}}
        {{form_field .Form "subject" nil}}
        {{form_field .Form "name" nil}}
        {{form_field .Form "email" nil}}
        {{form_field .Form "adults" nil}}
        {{if .AllowChildren}}{{form_field .Form "children" nil}}{{end}}
        <button>Register</button>
      {{form_close}}
      {{if .Capacity}}<p>{{.Left}} places left</p>{{end}}
    {{else if .Full}}<p>This event is full.</p>
    {{else if .Configured}}<p>Registration is closed.</p>{{end}}
  </div>
{{end}}

A successful registration sends a confirmation e-mail with the code, the total, the payment link and a link to the registration page. The visitor then lands on that page (/<page>/<code>?<key>=registered) when the module is placed on a page, and otherwise back on the form's page with ?<key>=registered&code=<code> (registrationCode reads it). Other results return to the form's page: ?<key>=full (not enough places left), ?<key>=closed (registration is not open), ?<key>=invalid (missing or wrong fields) or ?<key>=throttled (too many posts from the visitor). registrationResult reads the result.

Component

Instead of writing the form, a template can include the form component (see webthings.Module.Components): the sign-up box of a subject with plain, accessible default markup: prices, places left, the deadline, the result of the visitor's last post (with the code) and the form, or a notice when the subject is full or closed. Subjects without registration settings render nothing.

{{registrationForm "signup" .ID}}

It gets a FormView. A theme replaces it with <key>/form.gohtml, or registrations/form.gohtml for every instance; App.WriteTemplates(dir, key) writes the default there to start from. The default uses the classes wt-registration, wt-registration__title, wt-registration__facts and wt-registration__notes with the shared wt-form, wt-form__field, wt-form__row, wt-notice and wt-button, styled by the optional {{asset "webthings.css"}}; its texts go through tl, so the site's translations translate them.

Looking up and cancelling

Place the module on a page to let visitors find their registration by code. Below the page it serves:

/          registrations/lookup.gohtml        LookupView: a form asking for the code (?code=)
/{code}    registrations/registration.gohtml  RegistrationView: one registration

Every answer below the page, "not found" for a mistyped code included, is sent with "Cache-Control: private, no-store" and "X-Robots-Tag: noindex": the address holds the code and the page personal details, so no cache keeps them, no search engine indexes them, and neither the stats module nor the missed paths of the redirects module record them.

The cancel form posts to RegistrationView.CancelAction with the fields code and email (the address used to register, as confirmation): CancelInput, whose model is RegistrationView.Form. It returns to the element with the instance key as its id, with ?<key>=cancelled, or ?<key>=invalid when the address does not match.

Template functions

{{with registration "signup" .ID}}…{{end}}   Availability of a subject in the page's language
{{registerURL "signup"}}                      the address sign-up forms post to
{{registrationResult "signup"}}               the result of the visitor's last post on this page
{{registrationCode "signup"}}                 the code after registering on a page without the module
{{registrationForm "signup" .ID}}             the form component, rendered

Amounts are Cents in the instance's currency (Currency, EUR by default): {{money .Prices.Adult .Currency}} shows € 12,50 on a Dutch page.

Mail

The confirmation and the cancellation are mail templates (see webthings.Module.Mail) named confirmation and cancellation, with MailView as data, in the visitor's language. The defaults are English text in tl, so the site's translations translate them; a theme replaces them with mail/<key>/<name>.gohtml or mail/registrations/<name>.gohtml. Editors write the notes for registrants and the payment link per language.

Trash

Deleting a registration in the admin moves it to the admin's trash: it no longer takes places and leaves the lists, the counts, the CSV export and the lookup by code. Restoring it fails when its places are no longer free. Cancelling is something else: a cancelled registration stays in the list.

Index

Constants

View Source
const (
	// ResultRegistered is a sign-up that was taken.
	ResultRegistered = "registered"
	// ResultFull is a sign-up for more places than are left.
	ResultFull = "full"
	// ResultClosed is a sign-up for an event that takes none (any more).
	ResultClosed = "closed"
	// ResultInvalid is a sign-up with a missing or wrong field.
	ResultInvalid = "invalid"
	// ResultCancelled is a registration the visitor cancelled.
	ResultCancelled = "cancelled"
	// ResultThrottled is the answer to a visitor who posted too often.
	ResultThrottled = frontend.ResultThrottled
)

Results of visitor posts, sent back as ?<key>=<result>.

Variables

View Source
var (
	// ErrNotFound is returned when a subject or registration does not exist.
	ErrNotFound = db.ErrNotFound
	// ErrInvalid is returned for sign-ups with missing or wrong fields.
	ErrInvalid = errors.New("registrations_invalid")
	// ErrClosed is returned when registration is not open for the subject.
	ErrClosed = errors.New("registrations_closed")
	// ErrFull is returned when not enough places are left.
	ErrFull = errors.New("registrations_full")
	// ErrNoPlaces is returned when a registration in the trash cannot be
	// restored because its places were taken meanwhile.
	ErrNoPlaces = errors.New("registrations_no_places")
)
View Source
var ErrNoEvents = errors.New("registrations_no_events")

ErrNoEvents is returned when the instance is linked to a key (ForEvents) that names no events instance.

Functions

func Module

func Module(key, title string, opts ...Option) webthings.Module

Module adds a Registrations instance. key is used in URLs of the admin and in form actions and must be unique on the site; title is shown in the admin and the page editor.

Types

type Availability

type Availability struct {
	SubjectID string
	// Configured is true when editors set up registration for the subject,
	// open or not; without it a page shows no sign-up at all.
	Configured bool
	// Open is true while visitors can register: registration is switched on,
	// the deadline has not passed and places are left.
	Open bool
	// Closed is true when registration is switched off or its deadline
	// passed, and for subjects that are not Configured.
	Closed bool
	// Full is true when every place is taken.
	Full bool
	// Capacity is the number of places; 0 is unlimited.
	Capacity int
	// Taken is the number of places registered so far.
	Taken int
	// Left is the number of places left; 0 when Capacity is 0.
	Left int
	// ClosesAt is the deadline in the site's timezone; zero when there is none.
	ClosesAt      time.Time
	AllowChildren bool
	Prices        Prices
	// Currency is the ISO 4217 code of the prices, for {{money .Prices.Adult .Currency}}.
	Currency string
	// Notes are the editor's notes for registrants in the requested language,
	// or in the site's default language, rendered from Markdown.
	Notes template.HTML
	// Action is the address the sign-up form posts to.
	Action string
	// Form is the sign-up form's model (SignupInput) for go-form's
	// template functions, such as {{form_open .Form}} and {{form_field
	// .Form "name" nil}}, with the adults and children at most Left when
	// places are limited; it returns the visitor to the element with the
	// instance key as its id.
	Form form.RenderModel
}

Availability tells templates whether and how visitors can register for a subject.

type CancelInput

type CancelInput struct {
	Code  string `form:"input,hidden" name:"code"  required:"true" maxLength:"20"  line:"true"`
	Email string `` /* 143-byte string literal not displayed */
}

CancelInput is the cancel form a visitor posts to /_/<key>/cancel: the registration's code and the e-mail address it was made with.

type Cents

type Cents int64

Cents is an amount of money in hundredths, for example 1250 for 12.50. Templates show it with money, for example {{money .Total .Currency}}.

func ParseCents

func ParseCents(value string) (Cents, error)

ParseCents reads an amount such as "12", "12.5", "12.50" or "12,50". Empty is zero.

func (Cents) String

func (c Cents) String() string

String formats the amount with two decimals, for example "12.50", as editors type it.

type Fact

type Fact struct {
	Label string
	Value string
}

Fact is one setting in the summary; Label is translated.

type FormView

type FormView struct {
	// Key is the instance key.
	Key string
	Availability
	// Result is "registered", "full", "closed", "invalid", "cancelled",
	// "throttled" or "".
	Result string
	// Code is the visitor's registration code after registering here, when
	// the instance is placed on no page of its own.
	Code string
	// LookupURL is the page where visitors look up their registration, or ""
	// when the instance is placed on no page.
	LookupURL string
}

FormView is the data of the form component: whether and how visitors can register for a subject, with the result of the visitor's last post.

type LookupInput

type LookupInput struct {
	Code string `` /* 141-byte string literal not displayed */
}

LookupInput is the lookup form, LookupView.Form: the code from the confirmation, sent with method get as ?code=. Its field's id is registration-code.

type LookupView

type LookupView struct {
	// Title is the title of the page the module is mounted on.
	Title string
	// Action is the address the form sends its code field to, with method get.
	Action string
	// Code is the code that was looked up, if any.
	Code string
	// NotFound is set when no registration has Code.
	NotFound bool
	// Form is the lookup form's model (LookupInput, with Code), sent to
	// Action with method get, for go-form's template functions, such as
	// {{form_open .Form}} and {{form_field .Form "code" nil}}.
	Form form.RenderModel
}

LookupView is the data of registrations/lookup.gohtml: a form where visitors enter their code.

type MailView

type MailView struct {
	// Subject is what the visitor registered for; Start is set for events.
	Subject  Subject
	Code     string
	Name     string
	Adults   int
	Children int
	// Total is in Currency, for {{money .Total .Currency}}.
	Total    Cents
	Currency string
	// Payment is none, pending, paid or cancelled.
	Payment PaymentStatus
	// PaymentLink is the editor's payment link while payment is pending.
	PaymentLink string
	// Notes are the visitor's own remarks; Info the editor's notes for
	// registrants, as the Markdown they wrote, which reads well as text.
	Notes string
	Info  string
	// URL is the registration's page, to view or cancel it; empty when the
	// module is on no page.
	URL string
}

MailView is the data of the mail templates confirmation and cancellation, in the language the visitor registered in.

type NewSubjectView

type NewSubjectView struct {
	Title   string
	BackURL string
	Form    form.RenderModel
	Errors  form.FieldErrors
}

NewSubjectView adds a subject that is not an event.

type Option

type Option func(*options)

Option configures an instance.

func Currency

func Currency(code string) Option

Currency sets the ISO 4217 code of the prices, for example "GBP"; the default is "EUR". An unknown code stops the app from starting.

func ForEvents

func ForEvents(key string) Option

ForEvents links the instance to the events instance with key: editors pick its events in the admin, e-mail names the event, and registration closes when an event starts unless a deadline is set. Add that events instance to the app as well.

type OverviewRow

type OverviewRow struct {
	URL   string
	Title string
	Date  string
	// Status is "Open", "Closed" or "Full"; it is translated.
	Status        string
	Registrations int
	Places        string
}

OverviewRow is one event or subject in the overview, with its number of registrations and the places taken, out of the capacity when there is one.

type OverviewView

type OverviewView struct {
	Title string
	// Events is set when the subjects are events; rows then have a date.
	Events bool
	// NewURL adds a subject; empty for events and without the right.
	NewURL string
	// TrashURL shows the deleted registrations in the admin's trash.
	TrashURL string
	Rows     []OverviewRow
}

OverviewView lists the subjects with their registrations.

type PaymentStatus

type PaymentStatus string

PaymentStatus tells whether a registration was paid.

const (
	// PaymentNone is the status of free registrations.
	PaymentNone PaymentStatus = "none"
	// PaymentPending is the status of new registrations with a total.
	PaymentPending PaymentStatus = "pending"
	// PaymentPaid is set by an editor once the payment came in.
	PaymentPaid PaymentStatus = "paid"
	// PaymentCancelled is set when an unpaid registration is cancelled.
	PaymentCancelled PaymentStatus = "cancelled"
)

func (PaymentStatus) Valid

func (p PaymentStatus) Valid() bool

Valid reports whether status is one of the known statuses.

type Prices

type Prices struct {
	Adult Cents
	Child Cents
}

Prices are the prices per place.

func (Prices) Free

func (p Prices) Free() bool

Free reports whether registration costs nothing.

type Registration

type Registration struct {
	ID        string `db:"id"`
	SubjectID string `db:"subject_id"`
	// Code is the visitor's reference, for example "K7Q4-9M2X".
	Code       string        `db:"code"`
	Name       string        `db:"name"`
	Email      string        `db:"email"`
	Adults     int           `db:"adults"`
	Children   int           `db:"children"`
	Total      Cents         `db:"total"`
	Payment    PaymentStatus `db:"payment_status"`
	Notes      string        `db:"notes"`
	AdminNotes string        `db:"admin_notes"`
	// Locale is the language the visitor registered in.
	Locale      string     `db:"locale"`
	CreatedAt   time.Time  `db:"created_at"`
	CancelledAt *time.Time `db:"cancelled_at"`
	// CreatedBy is the editor who added the registration; empty for visitors.
	CreatedBy db.Ref `db:"created_by"`
	// UpdatedAt and UpdatedBy are the last change, by an editor or, when
	// cancelling, by the visitor (UpdatedBy empty).
	UpdatedAt time.Time `db:"updated_at"`
	UpdatedBy db.Ref    `db:"updated_by"`
	// DeletedAt is set while the registration is in the trash, with
	// DeletedBy.
	DeletedAt *time.Time `db:"deleted_at"`
	DeletedBy db.Ref     `db:"deleted_by"`
}

Registration is one sign-up.

func (Registration) Cancelled

func (r Registration) Cancelled() bool

Cancelled reports whether the registration was cancelled.

func (Registration) Places

func (r Registration) Places() int

Places is the number of places the registration takes.

type RegistrationAdminView

type RegistrationAdminView struct {
	Title        string
	BackURL      string
	Registration Registration
	// Total is the amount in the admin language, such as "€ 120,00";
	// Payment is the translated payment status.
	Total     string
	Payment   string
	Date      string
	Cancelled string
	// Form changes payment and admin notes; nil without the right.
	Form   *form.RenderModel
	Errors form.FieldErrors
	Cancel *form.RenderModel
	Delete *form.RenderModel
}

RegistrationAdminView shows one registration to editors.

type RegistrationRow

type RegistrationRow struct {
	URL       string
	Code      string
	Name      string
	Email     string
	Adults    int
	Children  int
	Total     string
	Payment   string
	Date      string
	Cancelled bool
}

RegistrationRow is one registration in the list of an event or subject; Cancelled registrations stay in the list.

type RegistrationView

type RegistrationView struct {
	// Key is the instance key; results arrive as ?<key>=<result>, and the
	// cancel form returns the visitor to the element with the id Key.
	Key string
	// Title is the title of the page the module is mounted on.
	Title string
	// Subject is what the visitor registered for; Start is set for events.
	Subject  Subject
	Code     string
	Name     string
	Adults   int
	Children int
	// Total is in Currency, for {{money .Total .Currency}}.
	Total    Cents
	Currency string
	// Payment is none, pending, paid or cancelled.
	Payment PaymentStatus
	// PaymentLink is the editor's payment link while payment is pending.
	PaymentLink string
	// Notes are the visitor's own remarks; Info the editor's notes for
	// registrants, in the page's language, rendered from Markdown.
	Notes string
	Info  template.HTML
	// CreatedAt is when the visitor registered, for {{date .CreatedAt}}.
	CreatedAt time.Time
	Cancelled bool
	// CancelAction is the address the cancel form posts to (fields code and
	// email); empty when the registration is cancelled.
	CancelAction string
	// Form is the cancel form's model (CancelInput, with Code) for go-form's
	// template functions, such as {{form_open .Form}} and {{form_field
	// .Form "email" nil}}; the zero value when the registration is
	// cancelled.
	Form form.RenderModel
	// Result is the outcome of the visitor's last post: "registered",
	// "cancelled", "invalid", "throttled" or empty.
	Result string
}

RegistrationView is the data of registrations/registration.gohtml.

type Service

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

Service is one Registrations instance, for the website's own code.

func Of

func Of(app *webthings.App, key string) *Service

Of returns the Registrations instance with key from a started app, or nil.

func (*Service) AllSettings

func (s *Service) AllSettings(ctx context.Context) ([]Settings, error)

AllSettings returns the settings of every subject, by title, without their texts.

func (*Service) Availability

func (s *Service) Availability(ctx context.Context, subjectID, locale string) (Availability, error)

Availability tells whether visitors can register for a subject now, with the notes for registrants in locale. A subject without settings is closed and not Configured.

func (*Service) ByCode

func (s *Service) ByCode(ctx context.Context, code string) (Registration, error)

ByCode returns the registration with code, or ErrNotFound; also when it is in the trash. The code may be typed loosely, for example "k7q4 9m2x".

func (*Service) Cancel

func (s *Service) Cancel(ctx context.Context, id string) error

Cancel cancels a registration, freeing its places. Unpaid registrations get payment status cancelled; paid ones stay paid so they can be refunded. Cancelling twice is harmless; a registration in the trash is ErrNotFound.

func (*Service) Currency

func (s *Service) Currency() string

Currency is the ISO 4217 code of the instance's prices, for example "EUR".

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id string) error

Delete moves a registration to the trash, freeing its places. One that is unknown or already in the trash is ErrNotFound.

func (*Service) Purge

func (s *Service) Purge(ctx context.Context, id string) error

Purge removes a registration in the trash for good; one that is not in the trash is ErrNotFound.

func (*Service) Register

func (s *Service) Register(ctx context.Context, signup Signup) (Registration, error)

Register signs a visitor up. It returns ErrInvalid for incomplete sign-ups, ErrClosed when registration is not open and ErrFull when not enough places are left. Concurrent sign-ups for one subject never exceed its capacity.

func (*Service) Registration

func (s *Service) Registration(ctx context.Context, id string) (Registration, error)

Registration returns one registration, or ErrNotFound; also when it is in the trash.

func (*Service) Registrations

func (s *Service) Registrations(ctx context.Context, subjectID string) ([]Registration, error)

Registrations returns every registration of a subject, cancelled ones included and those in the trash left out, in the order they came in.

func (*Service) SaveSettings

func (s *Service) SaveSettings(ctx context.Context, settings Settings) error

SaveSettings creates or replaces the settings of a subject.

func (*Service) Settings

func (s *Service) Settings(ctx context.Context, subjectID string) (Settings, error)

Settings returns the settings of a subject with its texts, or ErrNotFound.

func (*Service) Subject

func (s *Service) Subject(ctx context.Context, subjectID, locale string) (Subject, error)

Subject describes a subject in locale: the editor's title, or the event's.

func (*Service) Summaries

func (s *Service) Summaries(ctx context.Context) (map[string]Summary, error)

Summaries counts active registrations and places per subject.

func (*Service) Trashed

func (s *Service) Trashed(ctx context.Context, limit, offset int) ([]Registration, int, error)

Trashed returns registrations in the trash of every subject, most recently deleted first: at most limit of them from offset (all for a limit of 0), and how many the trash holds in all.

func (*Service) Undelete

func (s *Service) Undelete(ctx context.Context, id string) error

Undelete brings a registration back from the trash. An active one takes its places again, so it stays in the trash with ErrNoPlaces when the subject has not enough places left; a cancelled one comes back as it was. One that is not in the trash is ErrNotFound.

func (*Service) Update

func (s *Service) Update(ctx context.Context, id string, payment PaymentStatus, adminNotes string) error

Update changes the payment status and the admin notes of a registration.

type Settings

type Settings struct {
	SubjectID string `db:"subject_id"`
	// Title names the subject in the admin and e-mail. Events use their own
	// title when it is empty.
	Title string `db:"title"`
	// Open switches registration on.
	Open bool `db:"is_open"`
	// Capacity is the number of places (adults and children); 0 is unlimited.
	Capacity int `db:"capacity"`
	// ClosesAt is the registration deadline. Without one, registration for an
	// event closes when it starts.
	ClosesAt      *time.Time `db:"closes_at"`
	AdultPrice    Cents      `db:"adult_price"`
	ChildPrice    Cents      `db:"child_price"`
	AllowChildren bool       `db:"allow_children"`
	// UpdatedAt and UpdatedBy are the last change by an editor.
	UpdatedAt time.Time `db:"updated_at"`
	UpdatedBy db.Ref    `db:"updated_by"`
	// Texts are what registrants read, per language. SaveSettings stores the
	// languages given and keeps the others.
	Texts []SubjectText
}

Settings decide whether and how visitors can register for one subject.

func (Settings) Text

func (s Settings) Text(locale string) (SubjectText, bool)

Text returns the texts in locale, if written.

type SettingsView

type SettingsView struct {
	Title   string
	BackURL string
	Form    form.RenderModel
	Errors  form.FieldErrors
	// Tabs switch the language of Texts, what registrants read.
	Tabs       []admin.LocaleTab
	Texts      form.RenderModel
	TextErrors form.FieldErrors
}

SettingsView edits the settings of a subject.

type Signup

type Signup struct {
	SubjectID string
	Name      string
	Email     string
	Adults    int
	Children  int
	Notes     string
	Locale    string
}

Signup is what a visitor submits.

type SignupInput

type SignupInput struct {
	Subject  string `form:"input,hidden" name:"subject"  required:"true" maxLength:"64"   pattern:"^[A-Za-z0-9_.:\\-]+$"`
	Name     string `` /* 154-byte string literal not displayed */
	Email    string `` /* 171-byte string literal not displayed */
	Adults   int    `` /* 188-byte string literal not displayed */
	Children int    `` /* 188-byte string literal not displayed */
	Notes    string `` /* 241-byte string literal not displayed */
}

SignupInput is the sign-up form a visitor posts to /_/<key>/register: the subject, a name, an e-mail address, the number of adults (1 when empty) and children, and remarks. Themes render its fields with form_field, with their limits (Availability.Form), or write inputs with these names.

type Subject

type Subject struct {
	ID    string
	Title string
	// Start is when an event starts and End when it ends, in the event's
	// timezone; zero for other subjects. End is zero when the event has none,
	// and the last day of all-day events.
	Start  time.Time
	End    time.Time
	AllDay bool
	// URL is the event's page, when visitors can see it.
	URL string
}

Subject is what visitors register for, as the admin and e-mail show it.

func (Subject) When

func (s Subject) When() frontend.When

When is when the event takes place, as events.Event.When gives it; zero for other subjects.

type SubjectText

type SubjectText struct {
	Locale string `db:"locale"`
	// Notes are shown with the sign-up form, on the registration page and in
	// the confirmation. They are Markdown.
	Notes string `db:"notes"`
	// PaymentLink is shown while payment is pending, for example a payment
	// request URL or bank details.
	PaymentLink string `db:"payment_link"`
}

SubjectText is what registrants of a subject read in one language.

type SubjectView

type SubjectView struct {
	Title   string
	Date    string
	BackURL string
	// BackLabel names the overview BackURL leads to, as a translation key.
	BackLabel string
	// SettingsURL is empty without the right to change settings.
	SettingsURL string
	// ExportURL is empty without the right to export.
	ExportURL string
	Status    string
	Facts     []Fact
	Rows      []RegistrationRow
	// Registrations, Places and Total count active registrations.
	Registrations int
	Places        int
	Total         string
}

SubjectView shows one subject and its registrations.

type Summary

type Summary struct {
	SubjectID     string `db:"subject_id"`
	Registrations int    `db:"registrations"`
	Places        int    `db:"places"`
}

Summary counts the active registrations of one subject.

Jump to

Keyboard shortcuts

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