Skip to content

Commit

Permalink
location overrrides
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanfaerman committed Feb 14, 2024
1 parent 8416924 commit d41edda
Show file tree
Hide file tree
Showing 20 changed files with 662 additions and 181 deletions.
17 changes: 17 additions & 0 deletions internal/events/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ func init() {
register[AccountCreated]("account.created")
register[AccountProfileUpdated]("account.profile_updated")
register[AccountSessionOpened]("account.session_opened")
register[AccountEmailAdded]("account.email_added")
register[AccountEmailVerified]("account.email_verified")
register[AccountEmailRemoved]("account.email_removed")
}

type (
Expand All @@ -24,4 +27,18 @@ type (
IP string `json:"ip"`
ID int64 `json:"id"`
}

AccountEmailAdded struct {
Email string `json:"email"`
ID int64 `json:"id"`
}

AccountEmailVerified struct {
Email string `json:"email"`
ID int64 `json:"id"`
}

AccountEmailRemoved struct {
Email string `json:"email"`
}
)
1 change: 1 addition & 0 deletions internal/events/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package events
4 changes: 3 additions & 1 deletion internal/handlers/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ func (h account) Setup(w http.ResponseWriter, r *http.Request) {
return
}

http.Redirect(w, r, "/", http.StatusSeeOther)
w.Header().Set("HX-Redirect", "/")

// http.Redirect(w, r, "/", http.StatusSeeOther)

// TODO: update the profile, kick back errors if there are any
}
Expand Down
8 changes: 3 additions & 5 deletions internal/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package handlers

import (
"database/sql"
"net/http"
"sync"

"github.com/charmbracelet/log"
"github.com/davecgh/go-spew/spew"
"github.com/go-chi/chi"
"github.com/go-playground/form"
sse "github.com/r3labs/sse/v2"
Expand Down Expand Up @@ -60,9 +58,9 @@ func Setup(logger *log.Logger, db *sql.DB) error {
web.HookServerRoutes.Register(func(e hook.Event[web.Router]) {
for _, h := range global.handlers {
e.Payload.Routes().Group(h.Routes)
e.Payload.Routes().NotFound(func(w http.ResponseWriter, r *http.Request) {
spew.Dump(r)
})
// e.Payload.Routes().NotFound(func(w http.ResponseWriter, r *http.Request) {
// spew.Dump(r)
// })
}
})

Expand Down
6 changes: 2 additions & 4 deletions internal/handlers/memberships.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,17 @@ func (h Membership) Create(w http.ResponseWriter, r *http.Request) {
Kind: kind,
}

spew.Dump(r.Form)
if err := global.form.Decode(&group, r.Form); err != nil {
ErrorHandler(err)(w, r)
return
}
spew.Dump(group)
spew.Dump(r.Form.Get("callsign"))

if err := services.Membership.Create(ctx, services.Session.GetAccount(ctx), &group, r.Form.Get("callsign")); err != nil {
if err := services.Membership.Create(ctx, services.Session.GetAccount(ctx), &group, r.Form.Get("email"), r.Form.Get("callsign")); err != nil {
// TODO: handle this more gracefully
spew.Dump(err)
viewInput := views.MembershipCreateFormInput{
Name: group.Name,
Email: r.Form.Get("email"),
Slug: group.Slug,
Callsign: r.Form.Get("callsign"),
}
Expand Down
124 changes: 103 additions & 21 deletions internal/handlers/settings.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package handlers

import (
"fmt"
"net/http"

"github.com/davecgh/go-spew/spew"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/ryanfaerman/netctl/web/named"

. "github.com/ryanfaerman/netctl/internal/models/finders"
"modernc.org/sqlite"
)

type settings struct{}
Expand All @@ -27,6 +29,8 @@ func (h settings) Routes(r chi.Router) {

r.Get(named.Route("delegated-settings", "/settings/{slug}/{namespace}"), h.Settings)
r.Post(named.Route("delegated-settings-save", "/settings/{slug}/{namespace}/-/save"), h.SettingsSave)

r.Get(named.Route("verify-email", "/settings/{slug}/emails/-/verify"), h.VerifyEmail)
}

func (h settings) Settings(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -79,6 +83,8 @@ func (h settings) Settings(w http.ResponseWriter, r *http.Request) {
settings = account.Settings.PrivacySettings
case "appearance":
settings = account.Settings.AppearanceSettings
case "geolocation":
settings = account.Settings.LocationSettings
case "clubs":
clubs, err := account.Clubs(ctx)
if err != nil {
Expand All @@ -93,6 +99,8 @@ func (h settings) Settings(w http.ResponseWriter, r *http.Request) {
return
}
v.Memberships = orgs
case "emails":
settings = &models.Email{}
}

v.Show(namespace, settings).Render(ctx, w)
Expand Down Expand Up @@ -144,6 +152,7 @@ func (h settings) SettingsSave(w http.ResponseWriter, r *http.Request) {
settings models.Settings
viewSettings any
err error
email models.Email
)

switch namespace {
Expand All @@ -156,6 +165,13 @@ func (h settings) SettingsSave(w http.ResponseWriter, r *http.Request) {
case "appearance":
err = global.form.Decode(&settings.AppearanceSettings, r.Form)
viewSettings = settings.AppearanceSettings
case "geolocation":
err = global.form.Decode(&settings.LocationSettings, r.Form)
viewSettings = settings.LocationSettings
case "emails":
err = global.form.Decode(&email, r.Form)
viewSettings = &email

}

if err != nil {
Expand All @@ -165,38 +181,104 @@ func (h settings) SettingsSave(w http.ResponseWriter, r *http.Request) {

settingsErrs := map[string]string{}

// Account.SaveSettings validates settings as whole and has trouble
// when the input is a zero value. Until the service can handle zero values better,
// we need to validate this here.
if err := services.Validation.Apply(viewSettings); err != nil {
if errs, ok := err.(services.ValidationError); ok {
for field, e := range errs {
switch namespace {
case "emails":
if err := services.Validation.Apply(email); err != nil {
if errs, ok := err.(services.ValidationError); ok {
spew.Dump(errs)
switch field {
case "ProfileSettings.Name":
settingsErrs["name"] = e
case "ProfileSettings.About":
settingsErrs["about"] = e
case "PrivacySettings.Location":
settingsErrs["location"] = e
case "PrivacySettings.Visibility":
settingsErrs["visibility"] = e
case "AppearanceSettings.ActivityGraphs":
settingsErrs["activityGraphs"] = e

for field, e := range errs {
switch field {
case "Email.Address":
settingsErrs["email"] = e
}
}

v.ShowWithErrors(namespace, viewSettings, settingsErrs).Render(ctx, w)
return
}

ErrorHandler(err)(w, r)
return
}
ErrorHandler(err)(w, r)
return
default:
// Account.SaveSettings validates settings as whole and has trouble
// when the input is a zero value. Until the service can handle zero values better,
// we need to validate this here.
if err := services.Validation.Apply(viewSettings); err != nil {
if errs, ok := err.(services.ValidationError); ok {
for field, e := range errs {
switch field {
case "ProfileSettings.Name":
settingsErrs["name"] = e
case "ProfileSettings.About":
settingsErrs["about"] = e
case "PrivacySettings.Location":
settingsErrs["location"] = e
case "PrivacySettings.Visibility":
settingsErrs["visibility"] = e
case "AppearanceSettings.ActivityGraphs":
settingsErrs["activityGraphs"] = e
case "LocationSettings.Latitude":
settingsErrs["latitude"] = e
case "LocationSettings.Longitude":
settingsErrs["longitude"] = e
case "LocationSettings.TimeOffset":
settingsErrs["timeOffset"] = e

}
}

v.ShowWithErrors(namespace, viewSettings, settingsErrs).Render(ctx, w)
return
}
ErrorHandler(err)(w, r)
return

}
}

switch namespace {
case "emails":
fmt.Println("SAVED EMAILS")
if err := services.Account.AddEmail(ctx, account.ID, &email); err != nil {
spew.Dump(err)
if e, ok := err.(*sqlite.Error); ok {
switch e.Code() {
case 2067:
settingsErrs["email"] = "This email is already in use."
v.ShowWithErrors(namespace, viewSettings, settingsErrs).Render(ctx, w)
return
}
}
ErrorHandler(err)(w, r)
return
}
default:
if err := services.Account.SaveSettings(ctx, account.ID, &settings); err != nil {
ErrorHandler(err)(w, r)
return
}
}
v.Show(namespace, viewSettings).Render(ctx, w)
}

if err := services.Account.SaveSettings(ctx, account.ID, &settings); err != nil {
func (h settings) VerifyEmail(w http.ResponseWriter, r *http.Request) {
ctx := services.CSRF.GetContext(r.Context(), r)
slug := chi.URLParam(r, "slug")
token := r.URL.Query().Get("token")
account, err := FindOne[models.Account](ctx, BySlug(slug))
if err != nil {
ErrorHandler(err)(w, r)
return
}
v.Show(namespace, viewSettings).Render(ctx, w)
if err := services.Email.VerifyEmailAddition(ctx, account, token); err != nil {
ErrorHandler(err)(w, r)
return
}
if account.Kind != models.AccountKindUser {
http.Redirect(w, r, named.URLFor("delegated-settings", slug, "emails"), http.StatusSeeOther)
return
}
http.Redirect(w, r, named.URLFor("settings", "emails"), http.StatusSeeOther)
}
47 changes: 15 additions & 32 deletions internal/models/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ var AccountAnonymous = &Account{
}

type Account struct {
ID int64
Slug string `form:"slug" json:"slug"`
ID int64
Slug string `form:"slug" json:"slug"`
StreamID string `json:"stream_id"`

Name string `form:"name" validate:"required"`
About string `form:"about" json:"about"`
Expand Down Expand Up @@ -142,42 +143,17 @@ func (m *Account) Setting(ctx context.Context, path string) any {
return raw
}

func (u *Account) Emails() ([]Email, error) {
var emails []Email
rows, err := global.dao.GetEmailsForAccount(context.Background(), u.ID)
if err != nil {
return emails, err
}
for _, row := range rows {
email := Email{
ID: row.ID,
CreatedAt: row.Createdat,
UpdatedAt: row.Updatedat,
Address: row.Address,
IsPrimary: row.Isprimary,
IsPublic: row.Ispublic,
IsNotifiable: row.Isnotifiable,
}

if row.Verifiedat.Valid {
email.VerifiedAt = row.Verifiedat.Time
email.IsVerified = true
}

emails = append(emails, email)
}
return emails, nil
func (u *Account) Emails() ([]*Email, error) {
return Find[Email](context.Background(), ByAccount(u.ID))
}

func (m *Account) PrimaryEmail() (Email, error) {
emails, err := m.Emails()
if err != nil {
return Email{}, err
}
for _, email := range emails {
if email.IsPrimary {
return email, nil
}
if len(emails) > 0 {
return *emails[0], nil
}
return Email{}, errors.New("no primary email")
}
Expand Down Expand Up @@ -235,7 +211,6 @@ func FindAccountByCallsign(ctx context.Context, callsign string) (*Account, erro

func (u *Account) Callsigns() ([]Callsign, error) {
if len(u.callsigns) > 0 {
fmt.Println("using preloaded callsigns")
return u.callsigns, nil
}
var callsigns []Callsign
Expand Down Expand Up @@ -280,6 +255,14 @@ func (m *Account) Callsign() Callsign {
return calls[0]
}

func (m *Account) Location() (float64, float64) {
if m.Settings.LocationSettings.HasLocation() {
return m.Settings.LocationSettings.Location()
}
callsign := m.Callsign()
return callsign.Latitude, callsign.Longitude
}

var (
ErrAccountNeedsCallsign = errors.New("user needs a callsign")
ErrAccountNeedsName = errors.New("user needs a name")
Expand Down
13 changes: 13 additions & 0 deletions internal/models/account_finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func (m Account) Find(ctx context.Context, queries finders.QuerySet) (any, error
CreatedAt: raw.Createdat,
Settings: DefaultSettings,
Slug: raw.Slug,
StreamID: raw.StreamID,
}
if raw.Deletedat.Valid {
a.DeletedAt = raw.Deletedat.Time
Expand All @@ -135,6 +136,18 @@ func (m Account) Find(ctx context.Context, queries finders.QuerySet) (any, error
a.Name = a.Settings.ProfileSettings.Name
a.About = a.Settings.ProfileSettings.About

if !a.Settings.LocationSettings.HasLocation() {
callsigns, err := a.Callsigns()
if err == nil {
if len(callsigns) > 0 {
callsign := callsigns[0]
a.Settings.LocationSettings.Latitude = callsign.Latitude
a.Settings.LocationSettings.Longitude = callsign.Longitude
}
}
}

fmt.Println(a.Settings.LocationSettings)
switch {
case queries.HasField("callsigns"):
if _, err := (&a).Callsigns(); err != nil {
Expand Down
Loading

0 comments on commit d41edda

Please sign in to comment.