lunch/suggestions.go
2017-01-10 08:46:34 -05:00

317 lines
7.0 KiB
Go

package main
import (
"encoding/json"
"errors"
"gopkg.in/gorp.v1"
"log"
"net/http"
"strings"
"time"
)
type Suggestion struct {
SuggestionId int64
VetoingId int64 // -1 for initial suggestion
AttendeeId int64
GroupId int64 `json:"-"`
RestaurantName string
Date time.Time `json:"-"`
}
type PopularSuggestion struct {
RestaurantName string
Popularity int64
}
type SuggestionList struct {
Suggestions *[]*Suggestion `json:"suggestions"`
}
type PopularSuggestionList struct {
PopularSuggestions *[]*PopularSuggestion `json:"popularsuggestions"`
}
func (s *Suggestion) Write(w http.ResponseWriter) error {
enc := json.NewEncoder(w)
return enc.Encode(s)
}
func (s *Suggestion) Read(json_str string) error {
dec := json.NewDecoder(strings.NewReader(json_str))
return dec.Decode(s)
}
func (sl *SuggestionList) Write(w http.ResponseWriter) error {
enc := json.NewEncoder(w)
return enc.Encode(sl)
}
type SuggestionExistsError struct{}
func (aeu SuggestionExistsError) Error() string {
return "Suggestion exists"
}
type SuggestionNotLastError struct{}
func (snle SuggestionNotLastError) Error() string {
return "Suggestion not last on the stack"
}
func (s *PopularSuggestion) Write(w http.ResponseWriter) error {
enc := json.NewEncoder(w)
return enc.Encode(s)
}
func (sl *PopularSuggestionList) Write(w http.ResponseWriter) error {
enc := json.NewEncoder(w)
return enc.Encode(sl)
}
func GetAttendeesSuggestions(transaction *gorp.Transaction, groupid int64, date time.Time, attendeeid int64) (*[]*Suggestion, error) {
var suggestions []*Suggestion
_, err := transaction.Select(&suggestions, "SELECT * from suggestions WHERE GroupId=? AND Date=? AND AttendeeID=?", groupid, date, attendeeid)
if err != nil {
return nil, err
}
return &suggestions, nil
}
func GetSuggestions(groupid int64, date time.Time) (*[]*Suggestion, error) {
var suggestions []*Suggestion
_, err := DB.Select(&suggestions, "SELECT * from suggestions WHERE GroupId=? AND Date=?", groupid, date)
if err != nil {
return nil, err
}
return &suggestions, nil
}
func GetSuggestion(suggestionid int64, groupid int64, date time.Time) (*Suggestion, error) {
var s Suggestion
err := DB.SelectOne(&s, "SELECT * from suggestions where GroupId=? AND SuggestionId=? AND Date=?", groupid, suggestionid, date)
if err != nil {
return nil, err
}
return &s, nil
}
func VetoedBy(transaction *gorp.Transaction, suggestion *Suggestion) (*[]*Suggestion, error) {
var suggestions []*Suggestion
_, err := transaction.Select(&suggestions, "SELECT * from suggestions WHERE GroupId=? AND Date=? AND VetoingId=?", suggestion.GroupId, suggestion.Date, suggestion.SuggestionId)
if err != nil {
return nil, err
}
return &suggestions, nil
}
func GetPopularSuggestions() (*[]*PopularSuggestion, error) {
var suggestions []*Suggestion
suggestionMap := make(map[string]int64)
popularSuggestions := make([]*PopularSuggestion, 0)
_, err := DB.Select(&suggestions, "SELECT * from suggestions")
if err != nil {
return nil, err
}
for i := range suggestions {
suggestionMap[suggestions[i].RestaurantName] += 1
}
for name, count := range suggestionMap {
var popularSuggestion PopularSuggestion
popularSuggestion.RestaurantName = name
popularSuggestion.Popularity = count
popularSuggestions = append(popularSuggestions, &popularSuggestion)
}
return &popularSuggestions, nil
}
func InsertSuggestion(s *Suggestion) error {
transaction, err := DB.Begin()
if err != nil {
return err
}
existing, err := transaction.SelectInt("SELECT count(*) from suggestions where RestaurantName=? AND GroupId=? AND Date=?", s.RestaurantName, s.GroupId, s.Date)
if err != nil {
transaction.Rollback()
return err
}
if existing > 0 {
transaction.Rollback()
return SuggestionExistsError{}
}
err = transaction.Insert(s)
if err != nil {
transaction.Rollback()
return err
}
err = transaction.Commit()
if err != nil {
transaction.Rollback()
return err
}
return nil
}
func DeleteSuggestion(s *Suggestion) error {
transaction, err := DB.Begin()
if err != nil {
return err
}
// Ensure suggestion hasn't been vetoed
suggestions, err := VetoedBy(transaction, s)
if err != nil {
transaction.Rollback()
return err
}
if len(*suggestions) > 0 {
transaction.Rollback()
return SuggestionNotLastError{}
}
count, err := transaction.Delete(s)
if err != nil {
transaction.Rollback()
return err
}
if count != 1 {
transaction.Rollback()
return errors.New("Was going to delete more than one suggestion")
}
err = transaction.Commit()
if err != nil {
transaction.Rollback()
return err
}
return nil
}
func SuggestionHandler(w http.ResponseWriter, r *http.Request) {
user, err := GetUserFromSession(r)
if err != nil {
WriteError(w, 1 /*Not Signed In*/)
return
}
today := time.Now().UTC().Truncate(time.Hour * 24)
if r.Method == "POST" {
suggestion_json := r.PostFormValue("suggestion")
if suggestion_json == "" {
WriteError(w, 3 /*Invalid Request*/)
return
}
var suggestion Suggestion
err := suggestion.Read(suggestion_json)
if err != nil {
WriteError(w, 3 /*Invalid Request*/)
return
}
suggestion.SuggestionId = -1
suggestion.GroupId = user.GroupId
suggestion.Date = today
err = InsertSuggestion(&suggestion)
if err != nil {
if _, ok := err.(SuggestionExistsError); ok {
WriteError(w, 6 /*Suggestion Exists*/)
} else {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
}
return
}
w.WriteHeader(201 /*Created*/)
err = suggestion.Write(w)
if err != nil {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
return
}
} else if r.Method == "GET" {
var sl SuggestionList
suggestions, err := GetSuggestions(user.GroupId, today)
if err != nil {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
return
}
sl.Suggestions = suggestions
err = (&sl).Write(w)
if err != nil {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
return
}
} else if r.Method == "DELETE" {
suggestionid, err := GetURLID(r.URL.Path)
if err != nil {
WriteError(w, 3 /* Invalid Request */)
return
}
suggestion, err := GetSuggestion(suggestionid, user.GroupId, today)
if err != nil {
WriteError(w, 3 /*Invalid Request*/)
return
}
err = DeleteSuggestion(suggestion)
if err != nil {
if _, ok := err.(SuggestionNotLastError); ok {
WriteError(w, 8 /*Suggestion Not Last*/)
} else {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
}
return
}
WriteSuccess(w)
} else {
/* No PUT */
WriteError(w, 3 /*Invalid Request*/)
return
}
}
func PopularSuggestionHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
var sl PopularSuggestionList
suggestions, err := GetPopularSuggestions()
if err != nil {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
return
}
sl.PopularSuggestions = suggestions
err = (&sl).Write(w)
if err != nil {
WriteError(w, 999 /*Internal Error*/)
log.Print(err)
return
}
} else {
/* No POST, PUT, or DELETE */
WriteError(w, 3 /*Invalid Request*/)
return
}
}