From 4c7b9310c06df2931ffb3d5c0125ca90d4a2e1af Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Fri, 23 Dec 2016 20:38:59 -0500 Subject: [PATCH] Add restaurants --- db.go | 1 + errors.go | 1 + js/actions/AttendeeActions.js | 93 ++++++++++++++++++ js/actions/RestaurantActions.js | 93 ++++++++++++++++++ js/actions/UserActions.js | 4 + js/constants/AttendeeConstants.js | 8 ++ js/constants/RestaurantConstants.js | 8 ++ js/models.js | 27 ++++++ js/reducers/AttendeeReducer.js | 26 +++++ js/reducers/LunchReducer.js | 4 + js/reducers/RestaurantReducer.js | 26 +++++ main.go | 1 + restaurants.go | 143 ++++++++++++++++++++++++++++ 13 files changed, 435 insertions(+) create mode 100644 js/actions/AttendeeActions.js create mode 100644 js/actions/RestaurantActions.js create mode 100644 js/constants/AttendeeConstants.js create mode 100644 js/constants/RestaurantConstants.js create mode 100644 js/reducers/AttendeeReducer.js create mode 100644 js/reducers/RestaurantReducer.js create mode 100644 restaurants.go diff --git a/db.go b/db.go index 8e7e07e..98eb50a 100644 --- a/db.go +++ b/db.go @@ -19,6 +19,7 @@ func initDB() *gorp.DbMap { dbmap.AddTableWithName(User{}, "users").SetKeys(true, "UserId") dbmap.AddTableWithName(Session{}, "sessions").SetKeys(true, "SessionId") dbmap.AddTableWithName(Attendee{}, "attendees").SetKeys(true, "AttendeeId") + dbmap.AddTableWithName(Restaurant{}, "restaurants").SetKeys(true, "RestaurantId") err = dbmap.CreateTablesIfNotExists() if err != nil { diff --git a/errors.go b/errors.go index 165cfc3..6d8f34c 100644 --- a/errors.go +++ b/errors.go @@ -17,6 +17,7 @@ var error_codes = map[int]string{ 3: "Invalid Request", 4: "User Exists", 5: "Attendee Exists", + 6: "Restaurant Exists", // 5: "Connection Failed", //client-side error 999: "Internal Error", } diff --git a/js/actions/AttendeeActions.js b/js/actions/AttendeeActions.js new file mode 100644 index 0000000..c17e4a3 --- /dev/null +++ b/js/actions/AttendeeActions.js @@ -0,0 +1,93 @@ +var AttendeeConstants = require('../constants/AttendeeConstants'); + +var ErrorActions = require('./ErrorActions'); + +var models = require('../models.js'); +var Attendee = models.Attendee; +var Error = models.Error; + +function fetchAttendees() { + return { + type: AttendeeConstants.FETCH_ATTENDEES + } +} + +function attendeesFetched(attendees) { + return { + type: AttendeeConstants.ATTENDEES_FETCHED, + attendees: attendees + } +} + +function createAttendee() { + return { + type: AttendeeConstants.CREATE_ATTENDEE + } +} + +function attendeeCreated(attendee) { + return { + type: AttendeeConstants.ATTENDEE_CREATED, + attendee: attendee + } +} + +function fetchAll() { + return function (dispatch) { + dispatch(fetchAttendees()); + + $.ajax({ + type: "GET", + dataType: "json", + url: "attendee/", + success: function(data, status, jqXHR) { + var e = new Error(); + e.fromJSON(data); + if (e.isError()) { + ErrorActions.serverError(e); + } else { + dispatch(attendeesFetched(data.attendees.map(function(json) { + var a = new Attendee(); + a.fromJSON(json); + return a; + }))); + } + }, + error: function(jqXHR, status, error) { + ErrorActions.ajaxError(e); + } + }); + }; +} + +function create(attendee) { + return function (dispatch) { + dispatch(createAttendee()); + + $.ajax({ + type: "POST", + dataType: "json", + url: "attendee/", + data: {attendee: attendee.toJSON()}, + success: function(data, status, jqXHR) { + var e = new Error(); + e.fromJSON(data); + if (e.isError()) { + ErrorActions.serverError(e); + } else { + var a = new Attendee(); + a.fromJSON(data); + dispatch(attendeeCreated(a)); + } + }, + error: function(jqXHR, status, error) { + ErrorActions.ajaxError(e); + } + }); + }; +} + +module.exports = { + fetchAll: fetchAll, + create: create +}; diff --git a/js/actions/RestaurantActions.js b/js/actions/RestaurantActions.js new file mode 100644 index 0000000..fac8e3c --- /dev/null +++ b/js/actions/RestaurantActions.js @@ -0,0 +1,93 @@ +var RestaurantConstants = require('../constants/RestaurantConstants'); + +var ErrorActions = require('./ErrorActions'); + +var models = require('../models.js'); +var Restaurant = models.Restaurant; +var Error = models.Error; + +function fetchRestaurants() { + return { + type: RestaurantConstants.FETCH_RESTAURANTS + } +} + +function restaurantsFetched(restaurants) { + return { + type: RestaurantConstants.RESTAURANTS_FETCHED, + restaurants: restaurants + } +} + +function createRestaurant() { + return { + type: RestaurantConstants.CREATE_RESTAURANT + } +} + +function restaurantCreated(restaurant) { + return { + type: RestaurantConstants.RESTAURANT_CREATED, + restaurant: restaurant + } +} + +function fetchAll() { + return function (dispatch) { + dispatch(fetchRestaurants()); + + $.ajax({ + type: "GET", + dataType: "json", + url: "restaurant/", + 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) { + var a = new Restaurant(); + a.fromJSON(json); + return a; + }))); + } + }, + error: function(jqXHR, status, error) { + ErrorActions.ajaxError(e); + } + }); + }; +} + +function create(restaurant) { + return function (dispatch) { + dispatch(createRestaurant()); + + $.ajax({ + type: "POST", + dataType: "json", + url: "restaurant/", + data: {restaurant: restaurant.toJSON()}, + success: function(data, status, jqXHR) { + var e = new Error(); + e.fromJSON(data); + if (e.isError()) { + ErrorActions.serverError(e); + } else { + var a = new Restaurant(); + a.fromJSON(data); + dispatch(restaurantCreated(a)); + } + }, + error: function(jqXHR, status, error) { + ErrorActions.ajaxError(e); + } + }); + }; +} + +module.exports = { + fetchAll: fetchAll, + create: create +}; diff --git a/js/actions/UserActions.js b/js/actions/UserActions.js index 81ed4ac..c7929b0 100644 --- a/js/actions/UserActions.js +++ b/js/actions/UserActions.js @@ -1,5 +1,7 @@ var UserConstants = require('../constants/UserConstants'); +var AttendeeActions = require('./AttendeeActions'); +var RestaurantActions = require('./RestaurantActions'); var ErrorActions = require('./ErrorActions'); var models = require('../models.js'); @@ -89,6 +91,8 @@ function fetch(userId) { function initializeSession(dispatch, session) { dispatch(userLoggedIn(session)); dispatch(fetch(session.UserId)); + dispatch(AttendeeActions.fetchAll()); + dispatch(RestaurantActions.fetchAll()); } function login(user) { diff --git a/js/constants/AttendeeConstants.js b/js/constants/AttendeeConstants.js new file mode 100644 index 0000000..fb65aee --- /dev/null +++ b/js/constants/AttendeeConstants.js @@ -0,0 +1,8 @@ +var keyMirror = require('keymirror'); + +module.exports = keyMirror({ + FETCH_ATTENDEES: null, + ATTENDEES_FETCHED: null, + CREATE_ATTENDEE: null, + ATTENDEE_CREATED: null +}); diff --git a/js/constants/RestaurantConstants.js b/js/constants/RestaurantConstants.js new file mode 100644 index 0000000..a755478 --- /dev/null +++ b/js/constants/RestaurantConstants.js @@ -0,0 +1,8 @@ +var keyMirror = require('keymirror'); + +module.exports = keyMirror({ + FETCH_RESTAURANTS: null, + RESTAURANTS_FETCHED: null, + CREATE_RESTAURANT: null, + RESTAURANT_CREATED: null +}); diff --git a/js/models.js b/js/models.js index 3c29fdb..e21a67f 100644 --- a/js/models.js +++ b/js/models.js @@ -101,6 +101,33 @@ Attendee.prototype.isAttendee = function() { this.Name != empty_attendee.Name; } +function Restaurant() { + this.RestaurantId = -1; + this.Name = ""; +} + +Restaurant.prototype.toJSON = function() { + var json_obj = {}; + json_obj.RestaurantId = this.RestaurantId; + json_obj.Name = this.Name; + return JSON.stringify(json_obj); +} + +Restaurant.prototype.fromJSON = function(json_input) { + var json_obj = getJSONObj(json_input); + + if (json_obj.hasOwnProperty("RestaurantId")) + this.RestaurantId = json_obj.RestaurantId; + if (json_obj.hasOwnProperty("Name")) + this.Name = json_obj.Name; +} + +Restaurant.prototype.isRestaurant = function() { + var empty_attendee = new Restaurant(); + return this.RestaurantId != empty_attendee.RestaurantId || + this.Name != empty_attendee.Name; +} + function Error() { this.ErrorId = -1; this.ErrorString = ""; diff --git a/js/reducers/AttendeeReducer.js b/js/reducers/AttendeeReducer.js new file mode 100644 index 0000000..63ffe57 --- /dev/null +++ b/js/reducers/AttendeeReducer.js @@ -0,0 +1,26 @@ +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.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 AttendeeConstants.ATTENDEE_CREATED: + var attendee = action.attendee; + var attendees = assign({}, state, { + [attendee.AttendeeId]: attendee + }); + return attendees; + case UserConstants.USER_LOGGEDOUT: + return {}; + default: + return state; + } +}; diff --git a/js/reducers/LunchReducer.js b/js/reducers/LunchReducer.js index 27f1d22..9abcaff 100644 --- a/js/reducers/LunchReducer.js +++ b/js/reducers/LunchReducer.js @@ -2,10 +2,14 @@ var Redux = require('redux'); var UserReducer = require('./UserReducer'); var SessionReducer = require('./SessionReducer'); +var AttendeeReducer = require('./AttendeeReducer'); +var RestaurantReducer = require('./RestaurantReducer'); var ErrorReducer = require('./ErrorReducer'); module.exports = Redux.combineReducers({ user: UserReducer, session: SessionReducer, + attendees: AttendeeReducer, + restaurants: RestaurantReducer, error: ErrorReducer }); diff --git a/js/reducers/RestaurantReducer.js b/js/reducers/RestaurantReducer.js new file mode 100644 index 0000000..b0e23b5 --- /dev/null +++ b/js/reducers/RestaurantReducer.js @@ -0,0 +1,26 @@ +var assign = require('object-assign'); + +var RestaurantConstants = require('../constants/RestaurantConstants'); +var UserConstants = require('../constants/UserConstants'); + +module.exports = function(state = {}, action) { + switch (action.type) { + case RestaurantConstants.RESTAURANTS_FETCHED: + var restaurants = {}; + for (var i = 0; i < action.restaurants.length; i++) { + var restaurant = action.restaurants[i]; + restaurants[restaurant.RestaurantId] = restaurant; + } + return restaurants; + case RestaurantConstants.RESTAURANT_CREATED: + var restaurant = action.restaurant; + var restaurants = assign({}, state, { + [restaurant.RestaurantId]: restaurant + }); + return restaurants; + case UserConstants.USER_LOGGEDOUT: + return {}; + default: + return state; + } +}; diff --git a/main.go b/main.go index 8176088..d48b7ce 100644 --- a/main.go +++ b/main.go @@ -70,6 +70,7 @@ func main() { servemux.HandleFunc("/session/", SessionHandler) servemux.HandleFunc("/user/", UserHandler) servemux.HandleFunc("/attendee/", AttendeeHandler) + servemux.HandleFunc("/restaurant/", RestaurantHandler) listener, err := net.Listen("tcp", ":"+strconv.Itoa(port)) if err != nil { diff --git a/restaurants.go b/restaurants.go new file mode 100644 index 0000000..7e4313c --- /dev/null +++ b/restaurants.go @@ -0,0 +1,143 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" + "strings" +) + +type Restaurant struct { + RestaurantId int64 + Name string +} + +type RestaurantList struct { + Restaurants *[]*Restaurant `json:"restaurants"` +} + +func (r *Restaurant) Write(w http.ResponseWriter) error { + enc := json.NewEncoder(w) + return enc.Encode(r) +} + +func (r *Restaurant) Read(json_str string) error { + dec := json.NewDecoder(strings.NewReader(json_str)) + return dec.Decode(r) +} + +func (rl *RestaurantList) Write(w http.ResponseWriter) error { + enc := json.NewEncoder(w) + return enc.Encode(rl) +} + +type RestaurantExistsError struct{} + +func (aeu RestaurantExistsError) Error() string { + return "Restaurant exists" +} + +func GetRestaurants() (*[]*Restaurant, error) { + var restaurants []*Restaurant + + _, err := DB.Select(&restaurants, "SELECT * from restaurants") + if err != nil { + return nil, err + } + return &restaurants, nil +} + +func InsertRestaurant(r *Restaurant) error { + transaction, err := DB.Begin() + if err != nil { + return err + } + + existing, err := transaction.SelectInt("SELECT count(*) from users where Name=?", r.Name) + if err != nil { + transaction.Rollback() + return err + } + if existing > 0 { + transaction.Rollback() + return RestaurantExistsError{} + } + + err = transaction.Insert(r) + if err != nil { + transaction.Rollback() + return err + } + + err = transaction.Commit() + if err != nil { + transaction.Rollback() + return err + } + + return nil +} + +func RestaurantHandler(w http.ResponseWriter, r *http.Request) { + _, err := GetUserFromSession(r) + if err != nil { + WriteError(w, 1 /*Not Signed In*/) + return + } + + if r.Method == "POST" { + restaurant_json := r.PostFormValue("restaurant") + if restaurant_json == "" { + WriteError(w, 3 /*Invalid Request*/) + return + } + + var restaurant Restaurant + err := restaurant.Read(restaurant_json) + if err != nil { + WriteError(w, 3 /*Invalid Request*/) + return + } + restaurant.RestaurantId = -1 + + err = InsertRestaurant(&restaurant) + if err != nil { + if _, ok := err.(RestaurantExistsError); ok { + WriteError(w, 6 /*Restaurant Exists*/) + } else { + WriteError(w, 999 /*Internal Error*/) + log.Print(err) + } + return + } + + w.WriteHeader(201 /*Created*/) + err = restaurant.Write(w) + if err != nil { + WriteError(w, 999 /*Internal Error*/) + log.Print(err) + return + } + } else if r.Method == "GET" { + var rl RestaurantList + + restaurants, err := GetRestaurants() + if err != nil { + WriteError(w, 999 /*Internal Error*/) + log.Print(err) + return + } + + rl.Restaurants = restaurants + err = (&rl).Write(w) + if err != nil { + WriteError(w, 999 /*Internal Error*/) + log.Print(err) + return + } + } else { + /* No PUT or DELETE */ + WriteError(w, 3 /*Invalid Request*/) + return + } +}