diff --git a/internal/handlers/account.go b/internal/handlers/account.go
index b1661b6..21a5197 100644
--- a/internal/handlers/account.go
+++ b/internal/handlers/account.go
@@ -2,6 +2,7 @@ package handlers
import (
"net/http"
+ "strings"
"github.com/go-chi/chi"
@@ -19,7 +20,6 @@ func init() {
}
func (h account) Routes(r chi.Router) {
-
r.Use(services.Session.Middleware)
r.Group(func(r chi.Router) {
r.Use(middleware.HTMXOnly)
@@ -27,6 +27,10 @@ func (h account) Routes(r chi.Router) {
//
r.Post(named.Route("account-setup-apply", "/account/setup"), h.Setup)
})
+
+ r.Get(named.Route("account-profile", "/profile/{callsign}"), h.Show)
+ r.Get(named.Route("account-edit", "/profile/{callsign}/edit"), h.Edit)
+ r.Post(named.Route("account-edit-save", "/profile/{callsign}/edit/-/save"), h.Update)
}
func (h account) Setup(w http.ResponseWriter, r *http.Request) {
@@ -54,24 +58,10 @@ func (h account) Setup(w http.ResponseWriter, r *http.Request) {
return
}
- // callsign, err := hamdb.Lookup(r.Context(), input.Callsign)
- // if err != nil { ,
- // inputErrs.Callsign = "Could not validate callsign"
- // if err != hamdb.ErrNotFound {
- // global.log.Error("hamdb lookup failed", "error", err)
- // }
- //
- // ctx := services.CSRF.GetContext(r.Context(), r)
- //
- // (views.Dashboard{}).SetupaccountWithErrors(input, inputErrs).Render(ctx, w)
- // return
- // }
- // spew.Dump(callsign)
-
account, err := services.Session.GetAccount(r.Context())
if err != nil {
global.log.Error("unable to get account from session", "error", err)
- //views.Errors{}.Internal().Render(r.Context(), w)
+ // views.Errors{}.Internal().Render(r.Context(), w)
return
}
if err := services.Account.Setup(r.Context(), account.ID, input.Name, input.Callsign); err != nil {
@@ -95,3 +85,73 @@ func (h account) Setup(w http.ResponseWriter, r *http.Request) {
// TODO: update the profile, kick back errors if there are any
}
+
+func (h account) Show(w http.ResponseWriter, r *http.Request) {
+ callsign := chi.URLParam(r, "callsign")
+ ctx := services.CSRF.GetContext(r.Context(), r)
+
+ a, err := services.Account.FindByCallsign(ctx, callsign)
+ if err != nil {
+ ErrorHandler(err)(w, r)
+ return
+ }
+
+ v := views.Account{
+ Account: a,
+ }
+ v.Profile().Render(ctx, w)
+}
+
+func (h account) Edit(w http.ResponseWriter, r *http.Request) {
+ callsign := chi.URLParam(r, "callsign")
+ ctx := services.CSRF.GetContext(r.Context(), r)
+ a, err := services.Account.FindByCallsign(ctx, callsign)
+ if err != nil {
+ ErrorHandler(err)(w, r)
+ return
+ }
+ v := views.Account{
+ Account: a,
+ }
+ v.Edit().Render(ctx, w)
+}
+
+func (h account) Update(w http.ResponseWriter, r *http.Request) {
+ r.ParseForm()
+
+ callsign := chi.URLParam(r, "callsign")
+ ctx := services.CSRF.GetContext(r.Context(), r)
+ a, err := services.Account.FindByCallsign(ctx, callsign)
+ if err != nil {
+ ErrorHandler(err)(w, r)
+ return
+ }
+ v := views.Account{
+ Account: a,
+ }
+
+ inputErrs := views.AccountEditFormErrors{}
+ input := views.AccountEditFormInput{
+ Name: strings.TrimSpace(r.Form.Get("name")),
+ }
+ a.Name = input.Name
+ err = services.Account.Update(r.Context(), a)
+ if err != nil {
+ if errs, ok := err.(services.ValidationError); ok {
+ for field, e := range errs {
+ switch field {
+ case "Account.Name":
+ inputErrs.Name = e
+ }
+ }
+ v.EditFormWithErrors(input, inputErrs).Render(ctx, w)
+ return
+ }
+ ErrorHandler(err)(w, r)
+ return
+ }
+ // TODO: return this from the account.update method
+ v.Account = a
+
+ v.EditForm().Render(ctx, w)
+}
diff --git a/internal/models/account.go b/internal/models/account.go
index eb796ae..aa38e4a 100644
--- a/internal/models/account.go
+++ b/internal/models/account.go
@@ -17,7 +17,7 @@ const (
type Account struct {
ID int64
- Name string
+ Name string `validate:"required"`
Kind AccountKind
CreatedAt time.Time
@@ -122,6 +122,18 @@ func (u *Account) Callsigns() ([]Callsign, error) {
return callsigns, nil
}
+func (m *Account) Callsign() Callsign {
+ calls, err := m.Callsigns()
+ if err != nil {
+ return Callsign{}
+ }
+ if len(calls) == 0 {
+ return Callsign{}
+ }
+
+ return calls[0]
+}
+
var (
ErrAccountNeedsCallsign = errors.New("user needs a callsign")
ErrAccountNeedsName = errors.New("user needs a name")
diff --git a/internal/services/account.go b/internal/services/account.go
index 58cdd71..52e1d1c 100644
--- a/internal/services/account.go
+++ b/internal/services/account.go
@@ -22,6 +22,10 @@ func (account) FindByEmail(ctx context.Context, email string) (*models.Account,
return models.FindAccountByEmail(ctx, email)
}
+func (account) FindByCallsign(ctx context.Context, callsign string) (*models.Account, error) {
+ return models.FindAccountByCallsign(ctx, callsign)
+}
+
func (s account) CreateWithEmail(ctx context.Context, email string) (*models.Account, error) {
if u, err := s.FindByEmail(ctx, email); err != nil {
if err != sql.ErrNoRows {
@@ -67,7 +71,6 @@ var (
)
func (s account) Setup(ctx context.Context, id int64, name, callsign string) error {
-
account, err := global.dao.UpdateAccount(ctx, dao.UpdateAccountParams{
ID: id,
Name: name,
@@ -85,7 +88,6 @@ func (s account) Setup(ctx context.Context, id int64, name, callsign string) err
if account.ID != accountCallsign.ID {
return ErrAccountSetupCallsignTaken
}
-
}
fccCallsign, err := hamdb.Lookup(ctx, callsign)
@@ -144,9 +146,13 @@ func (s account) Setup(ctx context.Context, id int64, name, callsign string) err
return tx.Commit()
}
-// func (s account) AddCallsign(ctx context.Context, id int64, callsign string) error {
-// return global.dao.AddCallsignForaccount(ctx, dao.AddCallsignForaccountParams{
-// accountID: id,
-// Callsign: callsign,
-// })
-// }
+func (s account) Update(ctx context.Context, m *models.Account) error {
+ if err := Validation.Apply(m); err != nil {
+ return err
+ }
+ _, err := global.dao.UpdateAccount(ctx, dao.UpdateAccountParams{
+ ID: m.ID,
+ Name: m.Name,
+ })
+ return err
+}
diff --git a/internal/views/account.templ b/internal/views/account.templ
new file mode 100644
index 0000000..fc2c6b4
--- /dev/null
+++ b/internal/views/account.templ
@@ -0,0 +1,131 @@
+package views
+
+import "github.com/ryanfaerman/netctl/internal/models"
+import "github.com/ryanfaerman/netctl/web/named"
+
+type Account struct {
+ Account *models.Account
+}
+
+templ (v Account) Profile() {
+ @Page() {
+
+
+
+ "hello there { v.Account.Name }!"
+
+
+
+ }
+}
+
+templ (v Account) Edit() {
+ @Page() {
+
+
+
+ "Editing { v.Account.Name }!"
+ @v.EditForm()
+
+
+
+ }
+}
+
+type AccountEditFormInput struct {
+ Name string
+ About string
+}
+
+type AccountEditFormErrors struct {
+ Name string
+ About string
+}
+
+templ (v Account) EditForm() {
+ @v.EditFormWithErrors(
+ AccountEditFormInput{
+ Name: v.Account.Name,
+ },
+ AccountEditFormErrors{},
+ )
+}
+
+templ (v Account) EditFormWithErrors(input AccountEditFormInput, inputErrs AccountEditFormErrors) {
+ @Form("edit-account", FormAttrs{
+ Action: named.URLFor("account-edit-save", v.Account.Callsign().Call),
+ }) {
+ @InputText("name", InputAttrs{
+ Label: "Name",
+ Value: input.Name,
+ Error: inputErrs.Name,
+ HelpText: "Your name as you'd like to be called on the air",
+ })
+ @InputSubmit(InputAttrs{
+ Value: "Save",
+ })
+ }
+}
+
+templ (v Account) LocalBar() {
+
+}
diff --git a/internal/views/account_templ.go b/internal/views/account_templ.go
new file mode 100644
index 0000000..a9d4b56
--- /dev/null
+++ b/internal/views/account_templ.go
@@ -0,0 +1,413 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.513
+package views
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+import "github.com/ryanfaerman/netctl/internal/models"
+import "github.com/ryanfaerman/netctl/web/named"
+
+type Account struct {
+ Account *models.Account
+}
+
+func (v Account) Profile() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var3 := `"hello there `
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var4 string
+ templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(v.Account.Name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/views/account.templ`, Line: 16, Col: 33}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var5 := `!"`
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = Page().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func (v Account) Edit() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var9 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var9 == nil {
+ templ_7745c5c3_Var9 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var10 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var11 := `"Editing `
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var12 string
+ templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(v.Account.Name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/views/account.templ`, Line: 35, Col: 29}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Var13 := `!"`
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var13)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = v.EditForm().Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = Page().Render(templ.WithChildren(ctx, templ_7745c5c3_Var10), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+type AccountEditFormInput struct {
+ Name string
+ About string
+}
+
+type AccountEditFormErrors struct {
+ Name string
+ About string
+}
+
+func (v Account) EditForm() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var17 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var17 == nil {
+ templ_7745c5c3_Var17 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = v.EditFormWithErrors(
+ AccountEditFormInput{
+ Name: v.Account.Name,
+ },
+ AccountEditFormErrors{},
+ ).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func (v Account) EditFormWithErrors(input AccountEditFormInput, inputErrs AccountEditFormErrors) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var18 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var18 == nil {
+ templ_7745c5c3_Var18 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var19 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ templ_7745c5c3_Err = InputText("name", InputAttrs{
+ Label: "Name",
+ Value: input.Name,
+ Error: inputErrs.Name,
+ HelpText: "Your name as you'd like to be called on the air",
+ }).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = InputSubmit(InputAttrs{
+ Value: "Save",
+ }).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = Form("edit-account", FormAttrs{
+ Action: named.URLFor("account-edit-save", v.Account.Callsign().Call),
+ }).Render(templ.WithChildren(ctx, templ_7745c5c3_Var19), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func (v Account) LocalBar() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var20 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var20 == nil {
+ templ_7745c5c3_Var20 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}