2016-12-24 10:00:21 -05:00
package main
import (
"encoding/json"
2017-01-01 08:10:58 -05:00
"errors"
2016-12-29 21:22:35 -05:00
"gopkg.in/gorp.v1"
2016-12-24 10:00:21 -05:00
"log"
"net/http"
"strings"
"time"
)
type Suggestion struct {
SuggestionId int64
VetoingId int64 // -1 for initial suggestion
AttendeeId int64
UserId int64 ` json:"-" `
RestaurantName string
Date time . Time ` json:"-" `
}
2016-12-26 08:29:18 -05:00
type PopularSuggestion struct {
RestaurantName string
Popularity int64
}
2016-12-24 10:00:21 -05:00
type SuggestionList struct {
Suggestions * [ ] * Suggestion ` json:"suggestions" `
}
2016-12-26 08:29:18 -05:00
type PopularSuggestionList struct {
PopularSuggestions * [ ] * PopularSuggestion ` json:"popularsuggestions" `
}
2016-12-24 10:00:21 -05:00
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"
}
2017-01-01 08:10:58 -05:00
type SuggestionNotLastError struct { }
func ( snle SuggestionNotLastError ) Error ( ) string {
return "Suggestion not last on the stack"
}
2016-12-26 08:29:18 -05:00
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 )
}
2016-12-29 21:22:35 -05:00
func GetAttendeesSuggestions ( transaction * gorp . Transaction , userid int64 , date time . Time , attendeeid int64 ) ( * [ ] * Suggestion , error ) {
var suggestions [ ] * Suggestion
_ , err := transaction . Select ( & suggestions , "SELECT * from suggestions WHERE UserId=? AND Date=? AND AttendeeID=?" , userid , date , attendeeid )
if err != nil {
return nil , err
}
return & suggestions , nil
}
2016-12-24 10:00:21 -05:00
func GetSuggestions ( userid int64 , date time . Time ) ( * [ ] * Suggestion , error ) {
var suggestions [ ] * Suggestion
_ , err := DB . Select ( & suggestions , "SELECT * from suggestions WHERE UserId=? AND Date=?" , userid , date )
if err != nil {
return nil , err
}
return & suggestions , nil
}
2017-01-01 08:10:58 -05:00
func GetSuggestion ( suggestionid int64 , userid int64 , date time . Time ) ( * Suggestion , error ) {
var s Suggestion
err := DB . SelectOne ( & s , "SELECT * from suggestions where UserId=? AND SuggestionId=? AND Date=?" , userid , 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 UserId=? AND Date=? AND VetoingId=?" , suggestion . UserId , suggestion . Date , suggestion . SuggestionId )
if err != nil {
return nil , err
}
return & suggestions , nil
}
2016-12-26 08:29:18 -05:00
func GetPopularSuggestions ( ) ( * [ ] * PopularSuggestion , error ) {
var suggestions [ ] * Suggestion
2016-12-28 09:25:20 -05:00
suggestionMap := make ( map [ string ] int64 )
2016-12-26 08:29:18 -05:00
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
}
2016-12-24 10:00:21 -05:00
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 UserId=? AND Date=?" , s . RestaurantName , s . UserId , 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
}
2017-01-01 08:10:58 -05:00
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
}
2016-12-24 10:00:21 -05:00
func SuggestionHandler ( w http . ResponseWriter , r * http . Request ) {
user , err := GetUserFromSession ( r )
if err != nil {
WriteError ( w , 1 /*Not Signed In*/ )
return
}
2016-12-29 20:15:39 -05:00
today := time . Now ( ) . UTC ( ) . Truncate ( time . Hour * 24 )
2016-12-24 10:00:21 -05:00
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 . UserId = user . UserId
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 . UserId , 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
}
2017-01-01 08:10:58 -05:00
} 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 . UserId , 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 )
2016-12-24 10:00:21 -05:00
} else {
2017-01-01 08:10:58 -05:00
/* No PUT */
2016-12-24 10:00:21 -05:00
WriteError ( w , 3 /*Invalid Request*/ )
return
}
}
2016-12-26 08:29:18 -05:00
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
}
}