317 lines
7.0 KiB
Go
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
|
|
}
|
|
}
|