Add full ability to add/delete attendees
This commit is contained in:
parent
49893ffdb6
commit
350a30715a
63
attendees.go
63
attendees.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -71,7 +72,7 @@ func GetAttendees(userid int64, date time.Time) (*[]*Attendee, error) {
|
||||
|
||||
func GetPopularAttendees() (*[]*PopularAttendee, error) {
|
||||
var attendees []*Attendee
|
||||
var attendeeMap map[string]int64
|
||||
attendeeMap := make(map[string]int64)
|
||||
popularAttendees := make([]*PopularAttendee, 0)
|
||||
|
||||
_, err := DB.Select(&attendees, "SELECT * from attendees")
|
||||
@ -98,7 +99,7 @@ func InsertAttendee(a *Attendee) error {
|
||||
return err
|
||||
}
|
||||
|
||||
existing, err := transaction.SelectInt("SELECT count(*) from users where Name=?", a.Name)
|
||||
existing, err := transaction.SelectInt("SELECT count(*) from attendees where UserId=? AND Name=? AND Date=?", a.UserId, a.Name, a.Date)
|
||||
if err != nil {
|
||||
transaction.Rollback()
|
||||
return err
|
||||
@ -123,6 +124,41 @@ func InsertAttendee(a *Attendee) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAttendee(attendeeid int64, userid int64, date time.Time) (*Attendee, error) {
|
||||
var a Attendee
|
||||
|
||||
err := DB.SelectOne(&a, "SELECT * from attendees where UserId=? AND AttendeeId=? AND Date=?", userid, attendeeid, date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a, nil
|
||||
}
|
||||
|
||||
func DeleteAttendee(a *Attendee) error {
|
||||
transaction, err := DB.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count, err := transaction.Delete(a)
|
||||
if err != nil {
|
||||
transaction.Rollback()
|
||||
return err
|
||||
}
|
||||
if count != 1 {
|
||||
transaction.Rollback()
|
||||
return errors.New("Was going to delete more than one attendee")
|
||||
}
|
||||
|
||||
err = transaction.Commit()
|
||||
if err != nil {
|
||||
transaction.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func AttendeeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := GetUserFromSession(r)
|
||||
if err != nil {
|
||||
@ -184,8 +220,29 @@ func AttendeeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
} else if r.Method == "DELETE" {
|
||||
attendeeid, err := GetURLID(r.URL.Path)
|
||||
if err != nil {
|
||||
WriteError(w, 3 /* Invalid Request */)
|
||||
return
|
||||
}
|
||||
|
||||
attendee, err := GetAttendee(attendeeid, user.UserId, today)
|
||||
if err != nil {
|
||||
WriteError(w, 3 /*Invalid Request*/)
|
||||
return
|
||||
}
|
||||
|
||||
err = DeleteAttendee(attendee)
|
||||
if err != nil {
|
||||
WriteError(w, 999 /*Internal Error*/)
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
WriteSuccess(w)
|
||||
} else {
|
||||
/* No PUT or DELETE */
|
||||
/* No PUT */
|
||||
WriteError(w, 3 /*Invalid Request*/)
|
||||
return
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ var AttendeeConstants = require('../constants/AttendeeConstants');
|
||||
|
||||
var ErrorActions = require('./ErrorActions');
|
||||
|
||||
var models = require('../models.js');
|
||||
var Attendee = models.Attendee;
|
||||
var PopularAttendee = models.PopularAttendee;
|
||||
var Error = models.Error;
|
||||
|
||||
function fetchAttendees() {
|
||||
@ -32,6 +32,19 @@ function attendeeCreated(attendee) {
|
||||
}
|
||||
}
|
||||
|
||||
function removeAttendee() {
|
||||
return {
|
||||
type: AttendeeConstants.REMOVE_ATTENDEE
|
||||
}
|
||||
}
|
||||
|
||||
function attendeeRemoved(attendeeId) {
|
||||
return {
|
||||
type: AttendeeConstants.ATTENDEE_REMOVED,
|
||||
attendeeId: attendeeId
|
||||
}
|
||||
}
|
||||
|
||||
function fetchPopularAttendees() {
|
||||
return {
|
||||
type: AttendeeConstants.FETCH_POPULAR_ATTENDEES
|
||||
@ -114,8 +127,8 @@ function fetchPopular() {
|
||||
if (e.isError()) {
|
||||
ErrorActions.serverError(e);
|
||||
} else {
|
||||
dispatch(popularAttendeesFetched(data.attendees.map(function(json) {
|
||||
var a = new Attendee();
|
||||
dispatch(popularAttendeesFetched(data.popularattendees.map(function(json) {
|
||||
var a = new PopularAttendee();
|
||||
a.fromJSON(json);
|
||||
return a;
|
||||
})));
|
||||
@ -128,8 +141,33 @@ function fetchPopular() {
|
||||
};
|
||||
}
|
||||
|
||||
function remove(attendee) {
|
||||
return function(dispatch) {
|
||||
dispatch(removeAttendee());
|
||||
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
url: "attendee/"+attendee.AttendeeId+"/",
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
ErrorActions.serverError(e);
|
||||
} else {
|
||||
dispatch(attendeeRemoved(attendee.AttendeeId));
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, status, error) {
|
||||
ErrorActions.ajaxError(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchAll: fetchAll,
|
||||
create: create,
|
||||
remove: remove,
|
||||
fetchPopular: fetchPopular
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
var ErrorConstants = require('../constants/ErrorConstants');
|
||||
|
||||
var models = require('../models.js');
|
||||
var models = require('../models');
|
||||
var Error = models.Error;
|
||||
|
||||
function serverError(error) {
|
||||
|
@ -2,8 +2,9 @@ var SuggestionConstants = require('../constants/SuggestionConstants');
|
||||
|
||||
var ErrorActions = require('./ErrorActions');
|
||||
|
||||
var models = require('../models.js');
|
||||
var models = require('../models');
|
||||
var Suggestion = models.Suggestion;
|
||||
var PopularSuggestion = models.PopularSuggestion;
|
||||
var Error = models.Error;
|
||||
|
||||
function fetchSuggestions() {
|
||||
@ -114,8 +115,8 @@ function fetchPopular() {
|
||||
if (e.isError()) {
|
||||
ErrorActions.serverError(e);
|
||||
} else {
|
||||
dispatch(popularSuggestionsFetched(data.suggestions.map(function(json) {
|
||||
var a = new Suggestion();
|
||||
dispatch(popularSuggestionsFetched(data.popularsuggestions.map(function(json) {
|
||||
var a = new PopularSuggestion();
|
||||
a.fromJSON(json);
|
||||
return a;
|
||||
})));
|
||||
|
@ -4,7 +4,7 @@ var AttendeeActions = require('./AttendeeActions');
|
||||
var SuggestionActions = require('./SuggestionActions');
|
||||
var ErrorActions = require('./ErrorActions');
|
||||
|
||||
var models = require('../models.js');
|
||||
var models = require('../models');
|
||||
var User = models.User;
|
||||
var Session = models.Session;
|
||||
var Error = models.Error;
|
||||
|
@ -7,8 +7,9 @@ var Tab = ReactBootstrap.Tab;
|
||||
var Modal = ReactBootstrap.Modal;
|
||||
|
||||
var TopBarContainer = require('../containers/TopBarContainer');
|
||||
var NewUserForm = require('./NewUserForm');
|
||||
var RecordLunchContainer = require('../containers/RecordLunchContainer');
|
||||
var AccountSettingsModalContainer = require('../containers/AccountSettingsModalContainer');
|
||||
var NewUserForm = require('./NewUserForm');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "LunchApp",
|
||||
@ -62,7 +63,8 @@ module.exports = React.createClass({
|
||||
if (this.props.user.isUser())
|
||||
mainContent = (
|
||||
<Tabs defaultActiveKey={1} id='mainNavigationTabs'>
|
||||
<Tab title="New Entry" eventKey={1} >accounts
|
||||
<Tab title="Record Lunch" eventKey={1} >
|
||||
<RecordLunchContainer />
|
||||
</Tab>
|
||||
<Tab title="Statistics" eventKey={2} >stats will go here
|
||||
</Tab>
|
||||
|
71
js/components/RecordLunch.js
Normal file
71
js/components/RecordLunch.js
Normal file
@ -0,0 +1,71 @@
|
||||
var React = require('react');
|
||||
|
||||
var ReactBootstrap = require('react-bootstrap');
|
||||
var FormGroup = ReactBootstrap.FormGroup;
|
||||
var ControlLabel = ReactBootstrap.ControlLabel;
|
||||
|
||||
var Multiselect = require('react-widgets').Multiselect;
|
||||
|
||||
var models = require('../models')
|
||||
var Attendee = models.Attendee
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "RecordLunch",
|
||||
getInitialState: function() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
getAttendeeList: function() {
|
||||
var attendeeList = [];
|
||||
for (var attendeeId in this.props.attendees) {
|
||||
attendeeList.push(this.props.attendees[attendeeId]);
|
||||
}
|
||||
return attendeeList;
|
||||
},
|
||||
getAttendeeMap: function() {
|
||||
var attendeeMap = {};
|
||||
for (var attendeeId in this.props.attendees) {
|
||||
var attendee = this.props.attendees[attendeeId];
|
||||
attendeeMap[attendee.Name] = attendee;
|
||||
}
|
||||
return attendeeMap;
|
||||
},
|
||||
onChangeAttendees: function(attendees) {
|
||||
var attendeeMap = this.getAttendeeMap();
|
||||
for (var i in attendees) {
|
||||
if (attendeeMap.hasOwnProperty(attendees[i].Name)) {
|
||||
delete attendeeMap[attendees[i].Name];
|
||||
} else {
|
||||
var attendee = new Attendee();
|
||||
attendee.Name = attendees[i].Name;
|
||||
this.props.createAttendee(attendee);
|
||||
}
|
||||
}
|
||||
for (var i in attendeeMap) {
|
||||
this.props.removeAttendee(attendeeMap[i]);
|
||||
}
|
||||
},
|
||||
onCreateAttendee: function(attendeeName) {
|
||||
var attendee = new Attendee();
|
||||
attendee.Name = attendeeName;
|
||||
this.props.createAttendee(attendee);
|
||||
},
|
||||
render: function() {
|
||||
var attendeeList = this.getAttendeeList();
|
||||
return (
|
||||
<div><form>
|
||||
<FormGroup>
|
||||
<ControlLabel>Attendees</ControlLabel>
|
||||
<Multiselect
|
||||
value={attendeeList}
|
||||
data={this.props.popularAttendees}
|
||||
valueField='Name'
|
||||
textField='Name'
|
||||
messages={{'createNew': "(create new attendee)"}}
|
||||
onChange={this.onChangeAttendees}
|
||||
onCreate={this.onCreateAttendee} />
|
||||
</FormGroup>
|
||||
</form></div>
|
||||
);
|
||||
}
|
||||
});
|
@ -5,6 +5,8 @@ module.exports = keyMirror({
|
||||
ATTENDEES_FETCHED: null,
|
||||
CREATE_ATTENDEE: null,
|
||||
ATTENDEE_CREATED: null,
|
||||
REMOVE_ATTENDEE: null,
|
||||
ATTENDEE_REMOVED: null,
|
||||
FETCH_POPULAR_ATTENDEES: null,
|
||||
POPULAR_ATTENDEES_FETCHED: null
|
||||
});
|
||||
|
29
js/containers/RecordLunchContainer.js
Normal file
29
js/containers/RecordLunchContainer.js
Normal file
@ -0,0 +1,29 @@
|
||||
var connect = require('react-redux').connect;
|
||||
|
||||
var UserActions = require('../actions/UserActions');
|
||||
var AttendeeActions = require('../actions/AttendeeActions');
|
||||
var SuggestionActions = require('../actions/SuggestionActions');
|
||||
|
||||
var RecordLunch = require('../components/RecordLunch');
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
attendees: state.attendees,
|
||||
popularAttendees: state.popularAttendees,
|
||||
suggestions: state.suggestions,
|
||||
popularSuggestions: state.popularSuggestions
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
createAttendee: function(attendee) {dispatch(AttendeeActions.create(attendee))},
|
||||
removeAttendee: function(attendee) {dispatch(AttendeeActions.remove(attendee))},
|
||||
createSuggestion: function(suggestion) {dispatch(SuggestionActions.create(suggestion))}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(RecordLunch)
|
58
js/models.js
58
js/models.js
@ -101,6 +101,33 @@ Attendee.prototype.isAttendee = function() {
|
||||
this.Name != empty_attendee.Name;
|
||||
}
|
||||
|
||||
function PopularAttendee() {
|
||||
this.Name = "";
|
||||
this.Popularity = 0;
|
||||
}
|
||||
|
||||
PopularAttendee.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.Name = this.Name;
|
||||
json_obj.Popularity = this.Popularity;
|
||||
return JSON.stringify(json_obj);
|
||||
}
|
||||
|
||||
PopularAttendee.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("Popularity"))
|
||||
this.Popularity = json_obj.Popularity;
|
||||
if (json_obj.hasOwnProperty("Name"))
|
||||
this.Name = json_obj.Name;
|
||||
}
|
||||
|
||||
PopularAttendee.prototype.isPopularAttendee = function() {
|
||||
var empty_attendee = new PopularAttendee();
|
||||
return this.Popularity != empty_attendee.Popularity ||
|
||||
this.Name != empty_attendee.Name;
|
||||
}
|
||||
|
||||
function Suggestion() {
|
||||
this.SuggestionId = -1;
|
||||
this.VetoingId = -1;
|
||||
@ -134,6 +161,33 @@ Suggestion.prototype.isSuggestion = function() {
|
||||
this.RestaurantName != empty_suggestion.RestaurantName;
|
||||
}
|
||||
|
||||
function PopularSuggestion() {
|
||||
this.RestaurantName = "";
|
||||
this.Popularity = 0;
|
||||
}
|
||||
|
||||
PopularSuggestion.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.RestaurantName = this.RestaurantName;
|
||||
json_obj.Popularity = this.Popularity;
|
||||
return JSON.stringify(json_obj);
|
||||
}
|
||||
|
||||
PopularSuggestion.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("RestaurantName"))
|
||||
this.RestaurantName = json_obj.RestaurantName;
|
||||
if (json_obj.hasOwnProperty("Popularity"))
|
||||
this.Popularity = json_obj.Popularity;
|
||||
}
|
||||
|
||||
PopularSuggestion.prototype.isPopularSuggestion = function() {
|
||||
var empty_suggestion = new PopularSuggestion();
|
||||
return this.RestaurantName != empty_suggestion.RestaurantName &&
|
||||
this.Popularity != empty_suggestion.Popularity;
|
||||
}
|
||||
|
||||
function Error() {
|
||||
this.ErrorId = -1;
|
||||
this.ErrorString = "";
|
||||
@ -167,6 +221,10 @@ module.exports = models = {
|
||||
User: User,
|
||||
Session: Session,
|
||||
Error: Error,
|
||||
Attendee: Attendee,
|
||||
PopularAttendee: PopularAttendee,
|
||||
Suggestion: Suggestion,
|
||||
PopularSuggestion: PopularSuggestion,
|
||||
|
||||
// Constants
|
||||
BogusPassword: "password"
|
||||
|
@ -18,6 +18,10 @@ module.exports = function(state = {}, action) {
|
||||
[attendee.AttendeeId]: attendee
|
||||
});
|
||||
return attendees;
|
||||
case AttendeeConstants.ATTENDEE_REMOVED:
|
||||
var attendees = assign({}, state);
|
||||
delete attendees[action.attendeeId];
|
||||
return attendees;
|
||||
case UserConstants.USER_LOGGEDOUT:
|
||||
return {};
|
||||
default:
|
||||
|
@ -3,17 +3,17 @@ var assign = require('object-assign');
|
||||
var AttendeeConstants = require('../constants/AttendeeConstants');
|
||||
var UserConstants = require('../constants/UserConstants');
|
||||
|
||||
module.exports = function(state = {}, action) {
|
||||
module.exports = function(state = [], action) {
|
||||
switch (action.type) {
|
||||
case AttendeeConstants.POPULAR_ATTENDEES_FETCHED:
|
||||
var attendees = {};
|
||||
var attendees = [];
|
||||
for (var i = 0; i < action.attendees.length; i++) {
|
||||
var attendee = action.attendees[i];
|
||||
attendees[attendee.AttendeeId] = attendee;
|
||||
attendees.push(action.attendees[i]);
|
||||
}
|
||||
attendees.sort(function(a, b){return a.Popularity - b.Popularity});
|
||||
return attendees;
|
||||
case UserConstants.USER_LOGGEDOUT:
|
||||
return {};
|
||||
return [];
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -3,17 +3,17 @@ var assign = require('object-assign');
|
||||
var SuggestionConstants = require('../constants/SuggestionConstants');
|
||||
var UserConstants = require('../constants/UserConstants');
|
||||
|
||||
module.exports = function(state = {}, action) {
|
||||
module.exports = function(state = [], action) {
|
||||
switch (action.type) {
|
||||
case SuggestionConstants.POPULAR_SUGGESTIONS_FETCHED:
|
||||
var suggestions = {};
|
||||
var suggestions = [];
|
||||
for (var i = 0; i < action.suggestions.length; i++) {
|
||||
var suggestion = action.suggestions[i];
|
||||
suggestions[suggestion.SuggestionId] = suggestion;
|
||||
suggestions.push(action.suggestions[i]);
|
||||
}
|
||||
suggestions.sort(function(a, b){return a.Popularity - b.Popularity});
|
||||
return suggestions;
|
||||
case UserConstants.USER_LOGGEDOUT:
|
||||
return {};
|
||||
return [];
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -5,12 +5,14 @@ div#content {
|
||||
display: block;
|
||||
width: 95%;
|
||||
height: 100%;
|
||||
min-width: 75em;
|
||||
min-width: 20em;
|
||||
max-width: 100em;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
/* Keep the main windows sized to the full viewable height */
|
||||
.fullheight {
|
||||
height: 100%;
|
||||
div.tab-content {
|
||||
padding: 1em;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func GetSuggestions(userid int64, date time.Time) (*[]*Suggestion, error) {
|
||||
|
||||
func GetPopularSuggestions() (*[]*PopularSuggestion, error) {
|
||||
var suggestions []*Suggestion
|
||||
var suggestionMap map[string]int64
|
||||
suggestionMap := make(map[string]int64)
|
||||
popularSuggestions := make([]*PopularSuggestion, 0)
|
||||
|
||||
_, err := DB.Select(&suggestions, "SELECT * from suggestions")
|
||||
|
Loading…
Reference in New Issue
Block a user