Skip to content

Commit

Permalink
Registration Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
benpate committed Sep 12, 2024
1 parent a7022bc commit aac876d
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 106 deletions.
1 change: 1 addition & 0 deletions _embed/templates/admin-webhooks/template.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
steps:[
{
do: "edit"
options:["delete:/admin/webhooks/{{.WebhookID}}/delete"]
form: {
label: Edit Webhook
type: layout-vertical
Expand Down
7 changes: 7 additions & 0 deletions _embed/templates/registration-simple/confirm.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{- $message := .RegistrationData "confirmation" -}}

<div class="margin-bottom">{{- $message | markdown -}}</div>

<div>
<a href="/@me" class="button primary">Continue to Your New Profile &gt;</a>
</div>
55 changes: 45 additions & 10 deletions _embed/templates/registration-simple/registration.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,53 @@
properties: {
title: {type:"string"}
description: {type:"string"}
groupId: {type:"string", format:"objectId"}
confirmation: {type:"string"}
inboxTemplate: {type:"string"}
outboxTemplate: {type:"string"}
groupId: {type:"string"}
terms1: {type:"string"}
terms2: {type:"string"}
terms3: {type:"string"}
terms4: {type:"string"}
}
}
form: {
type:"layout-vertical",
children:[
{type:"select", path:"groupId", label:"Add to Group...", description:"New users will be added to this group", options:{provider:"groups"}},
{type:"text", path:"title", label:"Heading", description:"Displayed at the top of the registration form"}
{type:"textarea", path:"description", label:"Page Text", description:"Longer text above the registration form. Markdown is allowed.", options:{rows:8}}
{type:"text", path:"terms1", label:"Terms of Service"}
{type:"text", path:"terms2"}
{type:"text", path:"terms3"}
{type:"text", path:"terms4", description:"Populated lines will show as required checkboxes in the registration form."}
type: "layout-tabs",
children: [
{
type:"layout-vertical",
label:"Content",
children:[
{type:"text", path:"title", label:"Heading", description:"Displayed at the top of the registration form"}
{type:"textarea", path:"description", label:"Page Content", description:"Longer text above the registration form. Markdown is allowed.", options:{rows:8}}
]
},
{
type:"layout-vertical",
label:"Confirmation",
children:[
{type:"textarea", path:"confirmation", label:"Confirmation Message", description:"Confirmation message displayed when new users register. Markdown is allowed.", options:{rows:10}}
]
},
{
type:"layout-vertical",
label:"Rules"
children:[
{type:"select", path:"inboxTemplate", label:"Inbox", options:{provider:"inbox-templates"}},
{type:"select", path:"outboxTemplate", label:"Outbox", options:{provider:"outbox-templates"}},
{type:"select", path:"groupId", label:"Add to Group...", description:"New users will be added to this group", format:"objectId", options:{provider:"groups"}},
]
},
{
type:"layout-vertical",
label:"Terms",
children:[
{type:"text", path:"terms1", label:"Terms of Service will show as required checkboxes in the registration form."}
{type:"text", path:"terms2"}
{type:"text", path:"terms3"}
{type:"text", path:"terms4"}
]
}
]
}
actions: {
Expand All @@ -34,5 +64,10 @@
{do:"view-html", as-full-page:true}
]
}
confirm: {
steps:[
{do:"view-html"}
]
}
}
}
61 changes: 9 additions & 52 deletions _embed/templates/registration-simple/view.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{ $builder := . }}
{{- $builder := . }}
{{- $message := .QueryParam "message" -}}
{{- $iconURL := .IconURL -}}

Expand All @@ -14,13 +14,13 @@
<link rel="stylesheet" href="/.themes/default/stylesheet" rel="preload">
</head>

<body hx-target="main" hx-swap="innerHTML" hx-push-url="false" style="height:100vh">
<body hx-target="#card" hx-swap="innerHTML" hx-push-url="false" style="height:100vh">

<main class="flex-center" style="height:100vh;">

<div class="card" style="width:clamp(540px, 50%, 720px); margin:auto; padding:16px 32px; line-height:150%;">
<div id="card" class="card" style="width:clamp(540px, 50%, 720px); margin:auto; padding:16px 32px; line-height:150%;">

<form hx-post="/signin" hx-target="#message">
<form hx-post="/register" action="/register" method="post">

{{- if ne "" $iconURL -}}
<img src="{{$iconURL}}" class="block margin-auto" style="width:clamp(100px, 50%, 400px)">
Expand Down Expand Up @@ -81,10 +81,12 @@ <h1>{{.RegistrationData "title"}}</h1>
<span class="spin">{{icon "loading"}}</span> Registering
</button>

<button id="submitButton" type="submit" class="primary htmx-request-hide">
<button id="submitButton" type="submit" class="primary htmx-request-hide" tabindex="0">
Register Now
</button>

<a href="/" class="button">Cancel</a>

<span id="message" class="text-red" hidden></span>

<div class="margin-top-xl">
Expand All @@ -104,52 +106,7 @@ <h1>{{.RegistrationData "title"}}</h1>
<script type="text/javascript" src="/.themes/global/resources/htmx/htmx.min.js" rel="preload"></script>
<script type="text/javascript" src="/.themes/global/resources/hyperscript/_hyperscript.min.js" rel="preload"></script>
<script type="text/javascript" src="/.themes/global/javascript"></script>

<div script="on RegistrationSuccess from window go to url /@me"></div>
</body>
</html>

<!--
<div class="card padding-sm">
<form hx-post="/register" hx-swap="none" hx-push-url="false" class="pure-form pure-form-stacked">
<h1>{{.RegistrationData "title"}}</h1>
{{- if ne "" $message -}}
<div class="margin-bottom">{{$message}}</div>
{{- end -}}
<fieldset script="install eventValidator(name:'displayName')">
<label for="username">Your Name</label>
<input type="text" name="displayName" id="displayName" required="true" minlength="4" maxlength="40" autofocus autocomplete="off">
<div role="note" class="hint text-sm gray40">How others will see you.</div>
</fieldset>
<fieldset script="install eventValidator(name:'username')">
<label for="username">Username</label>
<input type="text" name="username" id="username" required="true" minlength="4" maxlength="40" autocomplete="off">
<div role="note" class="message text-sm gray40">How you'll sign in. Must be unique.</div>
</fieldset>
<fieldset class="margin-bottom" script="install eventValidator(name:'password')">
<label for="password">Password</label>
<input type="password" name="password" id="password" required="true" minlength="12" maxlength="100" autocomplete="off">
<div role="note" class="text-sm gray40">12 or more characters. Don't reuse passwords.</div>
</fieldset>
<div class="margin-top">
<button id="submitButton" type="submit" class="primary">
<span class="htmx-request-show">
{{icon "loading"}} Creating Your Profile...
</span>
<span class="htmx-request-hide">Register</span>
</button>
</div>
<div class="margin-top">
Already have a profile?
<a href="/signin">Sign In</a>
</div>
</form>
</div>
-->
104 changes: 60 additions & 44 deletions handler/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ func GetRegister(ctx *steranko.Context, factory *domain.Factory, domain *model.D

const location = "handler.GetRegister"

// If the user is already signed in, then just forward to their home page
if authorization := getAuthorization(ctx); authorization.IsAuthenticated() {
return ctx.Redirect(http.StatusFound, "/@me")
}

// Build the registration form
actionID := getActionID(ctx)

b, err := build.NewRegistration(factory, ctx.Request(), ctx.Response(), registration, actionID)
Expand All @@ -31,49 +37,6 @@ func GetRegister(ctx *steranko.Context, factory *domain.Factory, domain *model.D
return nil
}

// PostUpdateRegistration generates an echo.HandlerFunc that handles POST /register requests
func PostUpdateRegistration(ctx *steranko.Context, factory *domain.Factory, domain *model.Domain, registration *model.Registration) error {

const location = "handler.PostRegister"

// Collect User info
userInfo := struct {
Source string `json:"source"`
SourceID string `json:"sourceId"`
}{}

if err := ctx.Bind(&userInfo); err != nil {
return derp.Wrap(err, location, "Error binding user input")
}

// Collect transaction info
txn := model.NewRegistrationTxn()

if err := ctx.Bind(&txn); err != nil {
return derp.Wrap(err, location, "Error binding user input")
}

// Validate the Transaction
secret := domain.RegistrationData.GetString("secret")

if secret == "" {
return derp.NewNotFoundError(location, "Secret not found")
}

if !txn.IsValid(secret) {
return derp.NewBadRequestError(location, "Invalid Registration Transaction", txn)
}

// Update the User' registration
registrationService := factory.Registration()

if err := registrationService.UpdateRegistration(factory.Group(), factory.User(), domain, userInfo.Source, userInfo.SourceID, txn); err != nil {
return derp.Wrap(err, location, "Error updating user registration")
}

return ctx.NoContent(200)
}

// PostRegister generates an echo.HandlerFunc that handles POST /register requests
func PostRegister(ctx *steranko.Context, factory *domain.Factory, domain *model.Domain, registration *model.Registration) error {

Expand Down Expand Up @@ -113,7 +76,60 @@ func PostRegister(ctx *steranko.Context, factory *domain.Factory, domain *model.

ctx.SetCookie(&cookie)

// Build confirmation response
b, err := build.NewRegistration(factory, ctx.Request(), ctx.Response(), registration, "confirm")

if err != nil {
return derp.Wrap(err, location, "Error creating Builder")
}

if err := build.AsHTML(factory, ctx, b, build.ActionMethodGet); err != nil {
return derp.Wrap(err, location, "Error building HTML")
}

// Report success to the client
ctx.Response().Header().Add("Hx-Trigger", "RegistrationSuccess")
return nil
}

// PostUpdateRegistration generates an echo.HandlerFunc that handles POST /register requests
func PostUpdateRegistration(ctx *steranko.Context, factory *domain.Factory, domain *model.Domain, registration *model.Registration) error {

const location = "handler.PostRegister"

// Collect User info
userInfo := struct {
Source string `json:"source"`
SourceID string `json:"sourceId"`
}{}

if err := ctx.Bind(&userInfo); err != nil {
return derp.Wrap(err, location, "Error binding user input")
}

// Collect transaction info
txn := model.NewRegistrationTxn()

if err := ctx.Bind(&txn); err != nil {
return derp.Wrap(err, location, "Error binding user input")
}

// Validate the Transaction
secret := domain.RegistrationData.GetString("secret")

if secret == "" {
return derp.NewNotFoundError(location, "Secret not found")
}

if !txn.IsValid(secret) {
return derp.NewBadRequestError(location, "Invalid Registration Transaction", txn)
}

// Update the User' registration
registrationService := factory.Registration()

if err := registrationService.UpdateRegistration(factory.Group(), factory.User(), domain, userInfo.Source, userInfo.SourceID, txn); err != nil {
return derp.Wrap(err, location, "Error updating user registration")
}

return ctx.NoContent(200)
}
10 changes: 10 additions & 0 deletions service/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ func (service *Registration) Register(groupService *Group, userService *User, do
return model.User{}, derp.Wrap(err, location, "Error setting user data")
}

// If defined in the registration data, set the User's Inbox Template
if inboxTemplate := domain.RegistrationData.GetString("inboxTemplate"); inboxTemplate != "" {
user.InboxTemplate = inboxTemplate
}

// If defined in the registration data, set the User's Inbox Template
if outboxTemplate := domain.RegistrationData.GetString("outboxTemplate"); outboxTemplate != "" {
user.OutboxTemplate = outboxTemplate
}

// Try to save the User to the database
if err := userService.Save(&user, "Created by Online Registration"); err != nil {
return model.User{}, derp.Wrap(err, location, "Error creating new User")
Expand Down

0 comments on commit aac876d

Please sign in to comment.