Skip to content

Commit

Permalink
add profile page
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoegel committed Sep 22, 2024
1 parent f3dd2bd commit 7e40aeb
Show file tree
Hide file tree
Showing 14 changed files with 516 additions and 13 deletions.
1 change: 1 addition & 0 deletions pkg/pizza/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func init() {
Patch001,
Patch002,
Patch003,
Patch004,
}
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/pizza/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@ func Patch003(a *SQLAccessor) error {
_, err := a.db.Exec(stmt)
return err
}

func Patch004(a *SQLAccessor) error {
stmt := `ALTER TABLE friends ADD COLUMN preferences text default "{}";`
_, err := a.db.Exec(stmt)
return err
}
3 changes: 3 additions & 0 deletions pkg/pizza/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ func NewServer(config Config, metricsReg MetricsRegistry) (*Server, error) {
r.HandleFunc("/admin", s.HandleAdmin)
r.HandleFunc("/admin/edit", s.HandleAdminEdit)

r.HandleFunc("/profile", s.HandleGetProfile)
r.HandleFunc("/profile/edit", s.HandleUpdateProfile)

r.HandleFunc("/api/token", s.HandleAPIAuth)
r.HandleFunc("/api/friday", s.HandleAPIFriday)
r.HandleFunc("/api/friday/{ID}", s.HandleAPIFriday)
Expand Down
129 changes: 129 additions & 0 deletions pkg/pizza/server_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package pizza

import (
"html/template"
"net/http"
"path"

"github.com/mpoegel/rsvp.pizza/pkg/types"
zap "go.uber.org/zap"
)

type Preference struct {
Name string
IsSelected bool
}

type ProfilePageData struct {
LoggedIn bool
Name string
Toppings []Preference
Cheese []Preference
Sauce []Preference
Doneness []Preference
}

func (s *Server) HandleGetProfile(w http.ResponseWriter, r *http.Request) {
plate, err := template.ParseFiles(path.Join(s.config.StaticDir, "html/profile.html"))
if err != nil {
Log.Error("template index failure", zap.Error(err))
s.Handle500(w, r)
return
}

toppings := make(map[types.Topping]bool)
cheeses := make(map[types.Cheese]bool)
sauces := make(map[types.Sauce]bool)
var doneness types.Doneness

data := ProfilePageData{
LoggedIn: false,
}

claims, ok := s.authenticateRequest(r)
if ok {
data.LoggedIn = true
data.Name = claims.GivenName

prefs, err := s.store.GetPreferences(claims.Email)
if err != nil {
Log.Error("failed to get preferences", zap.Error(err), zap.String("email", claims.Email))
}
for _, t := range prefs.Toppings {
toppings[t] = true
}
for _, c := range prefs.Cheese {
cheeses[c] = true
}
for _, s := range prefs.Sauce {
sauces[s] = true
}
doneness = prefs.Doneness
}

data.Toppings = []Preference{
{Name: types.Banana_Peppers.String(), IsSelected: toppings[types.Banana_Peppers]},
{Name: types.Basil.String(), IsSelected: toppings[types.Basil]},
{Name: types.Barbecue_Chicken.String(), IsSelected: toppings[types.Barbecue_Chicken]},
{Name: types.Buffalo_Chicken.String(), IsSelected: toppings[types.Buffalo_Chicken]},
{Name: types.Jalapeno.String(), IsSelected: toppings[types.Jalapeno]},
{Name: types.Pepperoni.String(), IsSelected: toppings[types.Pepperoni]},
{Name: types.Prosciutto.String(), IsSelected: toppings[types.Prosciutto]},
{Name: types.Soppressata.String(), IsSelected: toppings[types.Soppressata]},
}
data.Cheese = []Preference{
{Name: types.Shredded_Mozzarella.String(), IsSelected: cheeses[types.Shredded_Mozzarella]},
{Name: types.Whole_Mozzarella.String(), IsSelected: cheeses[types.Whole_Mozzarella]},
{Name: types.Cheddar.String(), IsSelected: cheeses[types.Cheddar]},
{Name: types.Ricotta.String(), IsSelected: cheeses[types.Ricotta]},
}
data.Sauce = []Preference{
{Name: types.Raw_Tomatoes.String(), IsSelected: sauces[types.Raw_Tomatoes]},
{Name: types.Cooked_Tomatoes.String(), IsSelected: sauces[types.Cooked_Tomatoes]},
{Name: types.Basil_Pesto.String(), IsSelected: sauces[types.Basil_Pesto]},
}
data.Doneness = []Preference{
{Name: types.Well_Done.String(), IsSelected: doneness == types.Well_Done},
{Name: types.Medium_Well.String(), IsSelected: doneness == types.Medium_Well},
{Name: types.Medium.String(), IsSelected: doneness == types.Medium},
{Name: types.Medium_Rare.String(), IsSelected: doneness == types.Medium_Rare},
{Name: types.Rare.String(), IsSelected: doneness == types.Rare},
}

if err = plate.ExecuteTemplate(w, "Profile", data); err != nil {
Log.Error("template execution failure", zap.Error(err))
s.Handle500(w, r)
return
}
}

func (s *Server) HandleUpdateProfile(w http.ResponseWriter, r *http.Request) {
claims, ok := s.authenticateRequest(r)
if !ok {
w.Write(getToast("not logged in"))
return
}

if err := r.ParseForm(); err != nil {
Log.Error("form parse failure on profile edit", zap.Error(err))
w.Write(getToast("bad request"))
return
}

prefs := Preferences{
Toppings: types.ParseToppings(r.Form["toppings"]),
Cheese: types.ParseCheeses(r.Form["cheese"]),
Sauce: types.ParseSauces(r.Form["sauce"]),
Doneness: types.ParseDoneness(r.Form["doneness"][0]),
}

Log.Info("got profile update", zap.Any("preferences", prefs))

if err := s.store.SetPreferences(claims.Email, prefs); err != nil {
Log.Error("failed to set preferences", zap.Error(err), zap.String("email", claims.Email))
w.Write(getToast("failed to set preferences"))
return
}

w.Write(getToast("preferences updated"))
}
37 changes: 33 additions & 4 deletions pkg/pizza/sql_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pizza

import (
"database/sql"
"encoding/json"
"time"

_ "github.com/mattn/go-sqlite3"
Expand Down Expand Up @@ -118,7 +119,7 @@ func (a *SQLAccessor) GetUpcomingFridaysAfter(after time.Time, daysAhead int) ([
func (a *SQLAccessor) AddFriend(email, name string) error {
stmt, err := a.db.Prepare("INSERT INTO friends (email, name) VALUES (?, ?) ON CONFLICT (email) DO UPDATE SET name=?")
if err != nil {
return nil
return err
}
_, err = stmt.Exec(email, name, name)
return err
Expand Down Expand Up @@ -201,7 +202,7 @@ func (a *SQLAccessor) ListFridays() ([]Friday, error) {
func (a *SQLAccessor) RemoveFriend(email string) error {
stmt, err := a.db.Prepare("delete from friends where email = ?")
if err != nil {
return nil
return err
}
_, err = stmt.Exec(email)
return err
Expand All @@ -220,7 +221,7 @@ func (a *SQLAccessor) GetFriday(date time.Time) (Friday, error) {
func (a *SQLAccessor) RemoveFriday(date time.Time) error {
stmt, err := a.db.Prepare("delete from fridays where start_time = ?")
if err != nil {
return nil
return err
}
_, err = stmt.Exec(date)
return err
Expand All @@ -229,8 +230,36 @@ func (a *SQLAccessor) RemoveFriday(date time.Time) error {
func (a *SQLAccessor) UpdateFriday(friday Friday) error {
stmt, err := a.db.Prepare("UPDATE fridays SET invited_group=?, details=? WHERE start_time=?")
if err != nil {
return nil
return err
}
_, err = stmt.Exec(friday.Group, friday.Details, friday.Date)
return err
}

func (a *SQLAccessor) GetPreferences(email string) (Preferences, error) {
var prefs Preferences
stmt, err := a.db.Prepare("SELECT preferences FROM friends WHERE email=?")
if err != nil {
return prefs, err
}
var rawPreferences string
err = stmt.QueryRow(email).Scan(&rawPreferences)
if err != nil {
return prefs, err
}
err = json.Unmarshal([]byte(rawPreferences), &prefs)
return prefs, err
}

func (a *SQLAccessor) SetPreferences(email string, prefs Preferences) error {
rawPrefs, err := json.Marshal(prefs)
if err != nil {
return err
}
stmt, err := a.db.Prepare("UPDATE friends SET preferences=? WHERE email=?")
if err != nil {
return err
}
_, err = stmt.Exec(rawPrefs, email)
return err
}
12 changes: 12 additions & 0 deletions pkg/pizza/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package pizza

import (
"time"

"github.com/mpoegel/rsvp.pizza/pkg/types"
)

type Accessor interface {
Expand All @@ -22,6 +24,9 @@ type Accessor interface {
GetFriday(date time.Time) (Friday, error)
RemoveFriday(date time.Time) error
UpdateFriday(friday Friday) error

GetPreferences(email string) (Preferences, error)
SetPreferences(email string, preferences Preferences) error
}

type Friend struct {
Expand All @@ -34,3 +39,10 @@ type Friday struct {
Group *string
Details *string
}

type Preferences struct {
Toppings []types.Topping
Cheese []types.Cheese
Sauce []types.Sauce
Doneness types.Doneness
}
48 changes: 48 additions & 0 deletions pkg/types/cheese.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package types

type Cheese int

const (
Shredded_Mozzarella Cheese = iota + 1
Whole_Mozzarella
Cheddar
Ricotta
)

func ParseCheeses(cheeses []string) []Cheese {
res := make([]Cheese, 0)
for _, c := range cheeses {
res = append(res, ParseCheese(c))
}
return res
}

func ParseCheese(cheese string) Cheese {
switch cheese {
case "Shredded Mozzarella":
return Shredded_Mozzarella
case "Whole Mozzarella":
return Whole_Mozzarella
case "Cheddar":
return Cheddar
case "Ricotta":
return Ricotta
default:
return 0
}
}

func (c Cheese) String() string {
switch c {
case Shredded_Mozzarella:
return "Shredded Mozzarella"
case Whole_Mozzarella:
return "Whole Mozzarella"
case Cheddar:
return "Cheddar"
case Ricotta:
return "Ricotta"
default:
return ""
}
}
45 changes: 45 additions & 0 deletions pkg/types/doneness.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package types

type Doneness int

const (
Well_Done Doneness = iota + 1
Medium_Well
Medium
Medium_Rare
Rare
)

func ParseDoneness(doneness string) Doneness {
switch doneness {
case "Well Done":
return Well_Done
case "Medium Well":
return Medium_Well
case "Medium":
return Medium
case "Medium Rare":
return Medium_Rare
case "Rare":
return Rare
default:
return 0
}
}

func (d Doneness) String() string {
switch d {
case Well_Done:
return "Well Done"
case Medium_Well:
return "Medium Well"
case Medium:
return "Medium"
case Medium_Rare:
return "Medium Rare"
case Rare:
return "Rare"
default:
return ""
}
}
43 changes: 43 additions & 0 deletions pkg/types/sauce.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package types

type Sauce int

const (
Raw_Tomatoes Sauce = iota + 1
Cooked_Tomatoes
Basil_Pesto
)

func ParseSauces(sauces []string) []Sauce {
res := make([]Sauce, 0)
for _, s := range sauces {
res = append(res, ParseSauce(s))
}
return res
}

func ParseSauce(sauce string) Sauce {
switch sauce {
case "Raw Tomatoes":
return Raw_Tomatoes
case "Cooked Tomatoes":
return Cooked_Tomatoes
case "Basil Pesto":
return Basil_Pesto
default:
return 0
}
}

func (s Sauce) String() string {
switch s {
case Raw_Tomatoes:
return "Raw Tomatoes"
case Cooked_Tomatoes:
return "Cooked Tomatoes"
case Basil_Pesto:
return "Basil Pesto"
default:
return ""
}
}
Loading

0 comments on commit 7e40aeb

Please sign in to comment.