From c8232050da71c71e3a00d5485896abb6778c1cfe Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Mon, 26 Dec 2016 08:29:18 -0500 Subject: [PATCH] Add attendees and suggestions (except for UI) --- attendees.go | 67 +++++++++++++++++++++++++ js/actions/AttendeeActions.js | 44 +++++++++++++++- js/actions/SuggestionActions.js | 64 +++++++++++++++++++---- js/actions/UserActions.js | 2 + js/constants/AttendeeConstants.js | 4 +- js/constants/SuggestionConstants.js | 4 +- js/reducers/LunchReducer.js | 4 ++ js/reducers/PopularAttendeeReducer.js | 20 ++++++++ js/reducers/PopularSuggestionReducer.js | 20 ++++++++ main.go | 2 + suggestions.go | 66 ++++++++++++++++++++++++ 11 files changed, 283 insertions(+), 14 deletions(-) create mode 100644 js/reducers/PopularAttendeeReducer.js create mode 100644 js/reducers/PopularSuggestionReducer.js diff --git a/attendees.go b/attendees.go index bc12edf..715c563 100644 --- a/attendees.go +++ b/attendees.go @@ -15,10 +15,19 @@ type Attendee struct { Date time.Time `json:"-"` } +type PopularAttendee struct { + Name string + Popularity int64 +} + type AttendeeList struct { Attendees *[]*Attendee `json:"attendees"` } +type PopularAttendeeList struct { + PopularAttendees *[]*PopularAttendee `json:"popularattendees"` +} + func (a *Attendee) Write(w http.ResponseWriter) error { enc := json.NewEncoder(w) return enc.Encode(a) @@ -34,6 +43,16 @@ func (al *AttendeeList) Write(w http.ResponseWriter) error { return enc.Encode(al) } +func (pa *PopularAttendee) Write(w http.ResponseWriter) error { + enc := json.NewEncoder(w) + return enc.Encode(pa) +} + +func (pal *PopularAttendeeList) Write(w http.ResponseWriter) error { + enc := json.NewEncoder(w) + return enc.Encode(pal) +} + type AttendeeExistsError struct{} func (aeu AttendeeExistsError) Error() string { @@ -50,6 +69,29 @@ func GetAttendees(userid int64, date time.Time) (*[]*Attendee, error) { return &attendees, nil } +func GetPopularAttendees() (*[]*PopularAttendee, error) { + var attendees []*Attendee + var attendeeMap map[string]int64 + popularAttendees := make([]*PopularAttendee, 0) + + _, err := DB.Select(&attendees, "SELECT * from attendees") + if err != nil { + return nil, err + } + + for i := range attendees { + attendeeMap[attendees[i].Name] += 1 + } + for name, count := range attendeeMap { + var popularAttendee PopularAttendee + popularAttendee.Name = name + popularAttendee.Popularity = count + popularAttendees = append(popularAttendees, &popularAttendee) + } + + return &popularAttendees, nil +} + func InsertAttendee(a *Attendee) error { transaction, err := DB.Begin() if err != nil { @@ -148,3 +190,28 @@ func AttendeeHandler(w http.ResponseWriter, r *http.Request) { return } } + +func PopularAttendeeHandler(w http.ResponseWriter, r *http.Request) { + if r.Method == "GET" { + var pal PopularAttendeeList + + attendees, err := GetPopularAttendees() + if err != nil { + WriteError(w, 999 /*Internal Error*/) + log.Print(err) + return + } + + pal.PopularAttendees = attendees + err = (&pal).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 + } +} diff --git a/js/actions/AttendeeActions.js b/js/actions/AttendeeActions.js index c17e4a3..a17bd8a 100644 --- a/js/actions/AttendeeActions.js +++ b/js/actions/AttendeeActions.js @@ -32,6 +32,19 @@ function attendeeCreated(attendee) { } } +function fetchPopularAttendees() { + return { + type: AttendeeConstants.FETCH_POPULAR_ATTENDEES + } +} + +function popularAttendeesFetched(attendees) { + return { + type: AttendeeConstants.POPULAR_ATTENDEES_FETCHED, + attendees: attendees + } +} + function fetchAll() { return function (dispatch) { dispatch(fetchAttendees()); @@ -87,7 +100,36 @@ function create(attendee) { }; } +function fetchPopular() { + return function (dispatch) { + dispatch(fetchPopularAttendees()); + + $.ajax({ + type: "GET", + dataType: "json", + url: "popularattendees/", + success: function(data, status, jqXHR) { + var e = new Error(); + e.fromJSON(data); + if (e.isError()) { + ErrorActions.serverError(e); + } else { + dispatch(popularAttendeesFetched(data.attendees.map(function(json) { + var a = new Attendee(); + a.fromJSON(json); + return a; + }))); + } + }, + error: function(jqXHR, status, error) { + ErrorActions.ajaxError(e); + } + }); + }; +} + module.exports = { fetchAll: fetchAll, - create: create + create: create, + fetchPopular: fetchPopular }; diff --git a/js/actions/SuggestionActions.js b/js/actions/SuggestionActions.js index 320f080..c67cc51 100644 --- a/js/actions/SuggestionActions.js +++ b/js/actions/SuggestionActions.js @@ -12,10 +12,10 @@ function fetchSuggestions() { } } -function restaurantsFetched(restaurants) { +function suggestionsFetched(suggestions) { return { type: SuggestionConstants.SUGGESTIONS_FETCHED, - restaurants: restaurants + suggestions: suggestions } } @@ -25,10 +25,23 @@ function createSuggestion() { } } -function restaurantCreated(restaurant) { +function suggestionCreated(suggestion) { return { type: SuggestionConstants.SUGGESTION_CREATED, - restaurant: restaurant + suggestion: suggestion + } +} + +function fetchPopularSuggestions() { + return { + type: SuggestionConstants.FETCH_POPULAR_SUGGESTIONS + } +} + +function popularSuggestionsFetched(suggestions) { + return { + type: SuggestionConstants.POPULAR_SUGGESTIONS_FETCHED, + suggestions: suggestions } } @@ -39,14 +52,14 @@ function fetchAll() { $.ajax({ type: "GET", dataType: "json", - url: "restaurant/", + url: "suggestion/", success: function(data, status, jqXHR) { var e = new Error(); e.fromJSON(data); if (e.isError()) { ErrorActions.serverError(e); } else { - dispatch(restaurantsFetched(data.restaurants.map(function(json) { + dispatch(suggestionsFetched(data.suggestions.map(function(json) { var a = new Suggestion(); a.fromJSON(json); return a; @@ -60,15 +73,15 @@ function fetchAll() { }; } -function create(restaurant) { +function create(suggestion) { return function (dispatch) { dispatch(createSuggestion()); $.ajax({ type: "POST", dataType: "json", - url: "restaurant/", - data: {restaurant: restaurant.toJSON()}, + url: "suggestion/", + data: {suggestion: suggestion.toJSON()}, success: function(data, status, jqXHR) { var e = new Error(); e.fromJSON(data); @@ -77,7 +90,35 @@ function create(restaurant) { } else { var a = new Suggestion(); a.fromJSON(data); - dispatch(restaurantCreated(a)); + dispatch(suggestionCreated(a)); + } + }, + error: function(jqXHR, status, error) { + ErrorActions.ajaxError(e); + } + }); + }; +} + +function fetchPopular() { + return function (dispatch) { + dispatch(fetchPopularSuggestions()); + + $.ajax({ + type: "GET", + dataType: "json", + url: "popularsuggestions/", + success: function(data, status, jqXHR) { + var e = new Error(); + e.fromJSON(data); + if (e.isError()) { + ErrorActions.serverError(e); + } else { + dispatch(popularSuggestionsFetched(data.suggestions.map(function(json) { + var a = new Suggestion(); + a.fromJSON(json); + return a; + }))); } }, error: function(jqXHR, status, error) { @@ -89,5 +130,6 @@ function create(restaurant) { module.exports = { fetchAll: fetchAll, - create: create + create: create, + fetchPopular: fetchPopular }; diff --git a/js/actions/UserActions.js b/js/actions/UserActions.js index 65f6b2b..48bfde2 100644 --- a/js/actions/UserActions.js +++ b/js/actions/UserActions.js @@ -93,6 +93,8 @@ function initializeSession(dispatch, session) { dispatch(fetch(session.UserId)); dispatch(AttendeeActions.fetchAll()); dispatch(SuggestionActions.fetchAll()); + dispatch(AttendeeActions.fetchPopular()); + dispatch(SuggestionActions.fetchPopular()); } function login(user) { diff --git a/js/constants/AttendeeConstants.js b/js/constants/AttendeeConstants.js index fb65aee..6981835 100644 --- a/js/constants/AttendeeConstants.js +++ b/js/constants/AttendeeConstants.js @@ -4,5 +4,7 @@ module.exports = keyMirror({ FETCH_ATTENDEES: null, ATTENDEES_FETCHED: null, CREATE_ATTENDEE: null, - ATTENDEE_CREATED: null + ATTENDEE_CREATED: null, + FETCH_POPULAR_ATTENDEES: null, + POPULAR_ATTENDEES_FETCHED: null }); diff --git a/js/constants/SuggestionConstants.js b/js/constants/SuggestionConstants.js index c3def0b..fc96f40 100644 --- a/js/constants/SuggestionConstants.js +++ b/js/constants/SuggestionConstants.js @@ -4,5 +4,7 @@ module.exports = keyMirror({ FETCH_SUGGESTIONS: null, SUGGESTIONS_FETCHED: null, CREATE_SUGGESTION: null, - SUGGESTION_CREATED: null + SUGGESTION_CREATED: null, + FETCH_POPULAR_SUGGESTIONS: null, + POPULAR_SUGGESTIONS_FETCHED: null, }); diff --git a/js/reducers/LunchReducer.js b/js/reducers/LunchReducer.js index 303a40f..5195f73 100644 --- a/js/reducers/LunchReducer.js +++ b/js/reducers/LunchReducer.js @@ -3,13 +3,17 @@ var Redux = require('redux'); var UserReducer = require('./UserReducer'); var SessionReducer = require('./SessionReducer'); var AttendeeReducer = require('./AttendeeReducer'); +var PopularAttendeeReducer = require('./PopularAttendeeReducer'); var SuggestionReducer = require('./SuggestionReducer'); +var PopularSuggestionReducer = require('./PopularSuggestionReducer'); var ErrorReducer = require('./ErrorReducer'); module.exports = Redux.combineReducers({ user: UserReducer, session: SessionReducer, attendees: AttendeeReducer, + popularAttendees: PopularAttendeeReducer, suggestions: SuggestionReducer, + popularSuggestions: PopularSuggestionReducer, error: ErrorReducer }); diff --git a/js/reducers/PopularAttendeeReducer.js b/js/reducers/PopularAttendeeReducer.js new file mode 100644 index 0000000..86ca11f --- /dev/null +++ b/js/reducers/PopularAttendeeReducer.js @@ -0,0 +1,20 @@ +var assign = require('object-assign'); + +var AttendeeConstants = require('../constants/AttendeeConstants'); +var UserConstants = require('../constants/UserConstants'); + +module.exports = function(state = {}, action) { + switch (action.type) { + case AttendeeConstants.POPULAR_ATTENDEES_FETCHED: + var attendees = {}; + for (var i = 0; i < action.attendees.length; i++) { + var attendee = action.attendees[i]; + attendees[attendee.AttendeeId] = attendee; + } + return attendees; + case UserConstants.USER_LOGGEDOUT: + return {}; + default: + return state; + } +}; diff --git a/js/reducers/PopularSuggestionReducer.js b/js/reducers/PopularSuggestionReducer.js new file mode 100644 index 0000000..08b9580 --- /dev/null +++ b/js/reducers/PopularSuggestionReducer.js @@ -0,0 +1,20 @@ +var assign = require('object-assign'); + +var SuggestionConstants = require('../constants/SuggestionConstants'); +var UserConstants = require('../constants/UserConstants'); + +module.exports = function(state = {}, action) { + switch (action.type) { + case SuggestionConstants.POPULAR_SUGGESTIONS_FETCHED: + var suggestions = {}; + for (var i = 0; i < action.suggestions.length; i++) { + var suggestion = action.suggestions[i]; + suggestions[suggestion.SuggestionId] = suggestion; + } + return suggestions; + case UserConstants.USER_LOGGEDOUT: + return {}; + default: + return state; + } +}; diff --git a/main.go b/main.go index c3ae1e4..99feff3 100644 --- a/main.go +++ b/main.go @@ -70,7 +70,9 @@ func main() { servemux.HandleFunc("/session/", SessionHandler) servemux.HandleFunc("/user/", UserHandler) servemux.HandleFunc("/attendee/", AttendeeHandler) + servemux.HandleFunc("/popularattendees/", PopularAttendeeHandler) servemux.HandleFunc("/suggestion/", SuggestionHandler) + servemux.HandleFunc("/popularsuggestions/", PopularSuggestionHandler) listener, err := net.Listen("tcp", ":"+strconv.Itoa(port)) if err != nil { diff --git a/suggestions.go b/suggestions.go index 37581e3..352a73f 100644 --- a/suggestions.go +++ b/suggestions.go @@ -17,10 +17,19 @@ type Suggestion struct { 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) @@ -42,6 +51,16 @@ func (aeu SuggestionExistsError) Error() string { return "Suggestion exists" } +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 GetSuggestions(userid int64, date time.Time) (*[]*Suggestion, error) { var suggestions []*Suggestion @@ -52,6 +71,28 @@ func GetSuggestions(userid int64, date time.Time) (*[]*Suggestion, error) { return &suggestions, nil } +func GetPopularSuggestions() (*[]*PopularSuggestion, error) { + var suggestions []*Suggestion + var suggestionMap 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 { @@ -150,3 +191,28 @@ func SuggestionHandler(w http.ResponseWriter, r *http.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 + } +}