mirror of
				https://github.com/aclindsa/moneygo.git
				synced 2025-10-30 09:33:25 -04:00 
			
		
		
		
	Add per-user default currency
This commit is contained in:
		| @@ -5,6 +5,7 @@ var ErrorActions = require('./ErrorActions'); | |||||||
| var models = require('../models.js'); | var models = require('../models.js'); | ||||||
| var Security = models.Security; | var Security = models.Security; | ||||||
| var Error = models.Error; | var Error = models.Error; | ||||||
|  | var SecurityType = models.SecurityType; | ||||||
|  |  | ||||||
| function searchSecurityTemplates(searchString, searchType) { | function searchSecurityTemplates(searchString, searchType) { | ||||||
| 	return { | 	return { | ||||||
| @@ -23,6 +24,19 @@ function securityTemplatesSearched(searchString, searchType, securities) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function fetchCurrencyTemplates() { | ||||||
|  | 	return { | ||||||
|  | 		type: SecurityTemplateConstants.FETCH_CURRENCIES | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function currencyTemplatesFetched(currencies) { | ||||||
|  | 	return { | ||||||
|  | 		type: SecurityTemplateConstants.CURRENCIES_FETCHED, | ||||||
|  | 		currencies: currencies | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| function search(searchString, searchType, limit) { | function search(searchString, searchType, limit) { | ||||||
| 	return function (dispatch) { | 	return function (dispatch) { | ||||||
| 		dispatch(searchSecurityTemplates(searchString, searchType)); | 		dispatch(searchSecurityTemplates(searchString, searchType)); | ||||||
| @@ -57,6 +71,38 @@ function search(searchString, searchType, limit) { | |||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function fetchCurrencies() { | ||||||
|  | 	return function (dispatch) { | ||||||
|  | 		dispatch(fetchCurrencyTemplates()); | ||||||
|  |  | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "GET", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "securitytemplate/?search=&type=currency", | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					dispatch(ErrorActions.serverError(e)); | ||||||
|  | 				} else if (data.securities == null) { | ||||||
|  | 					dispatch(currencyTemplatesFetched(new Array())); | ||||||
|  | 				} else { | ||||||
|  | 					dispatch(currencyTemplatesFetched( | ||||||
|  | 							data.securities.map(function(json) { | ||||||
|  | 						var s = new Security(); | ||||||
|  | 						s.fromJSON(json); | ||||||
|  | 						return s; | ||||||
|  | 					}))); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				dispatch(ErrorActions.ajaxError(error)); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
| 	search: search | 	search: search, | ||||||
|  | 	fetchCurrencies: fetchCurrencies | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -12,6 +12,8 @@ var FormControl = ReactBootstrap.FormControl; | |||||||
| var ControlLabel = ReactBootstrap.ControlLabel; | var ControlLabel = ReactBootstrap.ControlLabel; | ||||||
| var Col = ReactBootstrap.Col; | var Col = ReactBootstrap.Col; | ||||||
|  |  | ||||||
|  | var Combobox = require('react-widgets').Combobox; | ||||||
|  |  | ||||||
| var models = require('../models'); | var models = require('../models'); | ||||||
| var User = models.User; | var User = models.User; | ||||||
|  |  | ||||||
| @@ -22,6 +24,7 @@ class AccountSettingsModal extends React.Component { | |||||||
| 			name: props ? props.user.Name: "", | 			name: props ? props.user.Name: "", | ||||||
| 			username: props ? props.user.Username : "", | 			username: props ? props.user.Username : "", | ||||||
| 			email: props ? props.user.Email : "", | 			email: props ? props.user.Email : "", | ||||||
|  | 			defaultCurrency: props ? props.user.DefaultCurrency : "", | ||||||
| 			password: models.BogusPassword, | 			password: models.BogusPassword, | ||||||
| 			confirm_password: models.BogusPassword, | 			confirm_password: models.BogusPassword, | ||||||
| 			passwordChanged: false, | 			passwordChanged: false, | ||||||
| @@ -33,6 +36,7 @@ class AccountSettingsModal extends React.Component { | |||||||
| 		this.state = this._getInitialState(); | 		this.state = this._getInitialState(); | ||||||
| 		this.onCancel = this.handleCancel.bind(this); | 		this.onCancel = this.handleCancel.bind(this); | ||||||
| 		this.onChange = this.handleChange.bind(this); | 		this.onChange = this.handleChange.bind(this); | ||||||
|  | 		this.onSelectCurrency = this.handleSelectCurrency.bind(this); | ||||||
| 		this.onSubmit = this.handleSubmit.bind(this); | 		this.onSubmit = this.handleSubmit.bind(this); | ||||||
| 	} | 	} | ||||||
| 	componentWillReceiveProps(nextProps) { | 	componentWillReceiveProps(nextProps) { | ||||||
| @@ -73,6 +77,13 @@ class AccountSettingsModal extends React.Component { | |||||||
| 			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value | 			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  | 	handleSelectCurrency(security) { | ||||||
|  | 		if (security.hasOwnProperty('SecurityId')) { | ||||||
|  | 			this.setState({ | ||||||
|  | 				defaultCurrency: security.SecurityId | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	handleSubmit(e) { | 	handleSubmit(e) { | ||||||
| 		var u = new User(); | 		var u = new User(); | ||||||
| 		e.preventDefault(); | 		e.preventDefault(); | ||||||
| @@ -81,6 +92,7 @@ class AccountSettingsModal extends React.Component { | |||||||
| 		u.Name = this.state.name; | 		u.Name = this.state.name; | ||||||
| 		u.Username = this.state.username; | 		u.Username = this.state.username; | ||||||
| 		u.Email = this.state.email; | 		u.Email = this.state.email; | ||||||
|  | 		u.DefaultCurrency = this.state.defaultCurrency; | ||||||
| 		if (this.state.passwordChanged) { | 		if (this.state.passwordChanged) { | ||||||
| 			u.Password = this.state.password; | 			u.Password = this.state.password; | ||||||
| 			if (u.Password != this.state.confirm_password) { | 			if (u.Password != this.state.confirm_password) { | ||||||
| @@ -130,6 +142,20 @@ class AccountSettingsModal extends React.Component { | |||||||
| 							ref="email"/> | 							ref="email"/> | ||||||
| 						</Col> | 						</Col> | ||||||
| 					</FormGroup> | 					</FormGroup> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Default Currency</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<Combobox | ||||||
|  | 							data={this.props.currencies} | ||||||
|  | 							valueField='SecurityId' | ||||||
|  | 							textField={item => item == undefined || typeof item === 'string' ? item : item.Name + " - " + item.Description} | ||||||
|  | 							defaultValue={this.state.defaultCurrency} | ||||||
|  | 							onChange={this.onSelectCurrency} | ||||||
|  | 							suggest | ||||||
|  | 							filter='contains' | ||||||
|  | 							ref="security" /> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
| 					<FormGroup validationState={this.passwordValidationState()}> | 					<FormGroup validationState={this.passwordValidationState()}> | ||||||
| 						<Col componentClass={ControlLabel} xs={2}>Password</Col> | 						<Col componentClass={ControlLabel} xs={2}>Password</Col> | ||||||
| 						<Col xs={10}> | 						<Col xs={10}> | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ class MoneyGoApp extends React.Component { | |||||||
| 	} | 	} | ||||||
| 	componentDidMount() { | 	componentDidMount() { | ||||||
| 		this.props.tryResumingSession(); | 		this.props.tryResumingSession(); | ||||||
|  | 		this.props.fetchCurrencies(); | ||||||
| 	} | 	} | ||||||
| 	handleShowSettings() { | 	handleShowSettings() { | ||||||
| 		this.setState({showAccountSettingsModal: true}); | 		this.setState({showAccountSettingsModal: true}); | ||||||
|   | |||||||
| @@ -11,6 +11,8 @@ var Col = ReactBootstrap.Col; | |||||||
| var Button = ReactBootstrap.Button; | var Button = ReactBootstrap.Button; | ||||||
| var ButtonGroup = ReactBootstrap.ButtonGroup; | var ButtonGroup = ReactBootstrap.ButtonGroup; | ||||||
|  |  | ||||||
|  | var Combobox = require('react-widgets').Combobox; | ||||||
|  |  | ||||||
| var models = require('../models'); | var models = require('../models'); | ||||||
| var User = models.User; | var User = models.User; | ||||||
|  |  | ||||||
| @@ -22,6 +24,7 @@ class NewUserModal extends React.Component { | |||||||
| 			name: "", | 			name: "", | ||||||
| 			username: "", | 			username: "", | ||||||
| 			email: "", | 			email: "", | ||||||
|  | 			defaultCurrency: '840', // ISO4217 code for USD | ||||||
| 			password: "", | 			password: "", | ||||||
| 			confirm_password: "", | 			confirm_password: "", | ||||||
| 			passwordChanged: false, | 			passwordChanged: false, | ||||||
| @@ -29,6 +32,7 @@ class NewUserModal extends React.Component { | |||||||
| 		}; | 		}; | ||||||
| 		this.onCancel = this.handleCancel.bind(this); | 		this.onCancel = this.handleCancel.bind(this); | ||||||
| 		this.onChange = this.handleChange.bind(this); | 		this.onChange = this.handleChange.bind(this); | ||||||
|  | 		this.onSelectCurrency = this.handleSelectCurrency.bind(this); | ||||||
| 		this.onSubmit = this.handleSubmit.bind(this); | 		this.onSubmit = this.handleSubmit.bind(this); | ||||||
| 	} | 	} | ||||||
| 	passwordValidationState() { | 	passwordValidationState() { | ||||||
| @@ -64,6 +68,13 @@ class NewUserModal extends React.Component { | |||||||
| 			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value | 			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  | 	handleSelectCurrency(security) { | ||||||
|  | 		if (security.hasOwnProperty('SecurityId')) { | ||||||
|  | 			this.setState({ | ||||||
|  | 				defaultCurrency: security.AlternateId | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	handleSubmit(e) { | 	handleSubmit(e) { | ||||||
| 		var u = new User(); | 		var u = new User(); | ||||||
| 		var error = ""; | 		var error = ""; | ||||||
| @@ -72,6 +83,7 @@ class NewUserModal extends React.Component { | |||||||
| 		u.Name = this.state.name; | 		u.Name = this.state.name; | ||||||
| 		u.Username = this.state.username; | 		u.Username = this.state.username; | ||||||
| 		u.Email = this.state.email; | 		u.Email = this.state.email; | ||||||
|  | 		u.DefaultCurrency = Number.parseInt(this.state.defaultCurrency); | ||||||
| 		u.Password = this.state.password; | 		u.Password = this.state.password; | ||||||
| 		if (u.Password != this.state.confirm_password) { | 		if (u.Password != this.state.confirm_password) { | ||||||
| 			this.setState({error: "Error: passwords do not match"}); | 			this.setState({error: "Error: passwords do not match"}); | ||||||
| @@ -118,6 +130,20 @@ class NewUserModal extends React.Component { | |||||||
| 							ref="email"/> | 							ref="email"/> | ||||||
| 						</Col> | 						</Col> | ||||||
| 					</FormGroup> | 					</FormGroup> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Default Currency</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<Combobox | ||||||
|  | 							data={this.props.currencies} | ||||||
|  | 							valueField='AlternateId' | ||||||
|  | 							textField={item => typeof item === 'string' ? item : item.Name + " - " + item.Description} | ||||||
|  | 							defaultValue={this.state.defaultCurrency} | ||||||
|  | 							onChange={this.onSelectCurrency} | ||||||
|  | 							suggest | ||||||
|  | 							filter='contains' | ||||||
|  | 							ref="security" /> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
| 					<FormGroup validationState={this.passwordValidationState()}> | 					<FormGroup validationState={this.passwordValidationState()}> | ||||||
| 						<Col componentClass={ControlLabel} xs={2}>Password</Col> | 						<Col componentClass={ControlLabel} xs={2}>Password</Col> | ||||||
| 						<Col xs={10}> | 						<Col xs={10}> | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| var keyMirror = require('keymirror'); | var keyMirror = require('keymirror'); | ||||||
|  |  | ||||||
| module.exports = keyMirror({ | module.exports = keyMirror({ | ||||||
|  | 	FETCH_CURRENCIES: null, | ||||||
|  | 	CURRENCIES_FETCHED: null, | ||||||
| 	SEARCH_SECURITY_TEMPLATES: null, | 	SEARCH_SECURITY_TEMPLATES: null, | ||||||
| 	SECURITY_TEMPLATES_SEARCHED: null | 	SECURITY_TEMPLATES_SEARCHED: null | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -1,11 +1,13 @@ | |||||||
| var connect = require('react-redux').connect; | var connect = require('react-redux').connect; | ||||||
|  |  | ||||||
| var UserActions = require('../actions/UserActions'); | var UserActions = require('../actions/UserActions'); | ||||||
|  |  | ||||||
| var AccountSettingsModal = require('../components/AccountSettingsModal'); | var AccountSettingsModal = require('../components/AccountSettingsModal'); | ||||||
|  |  | ||||||
| function mapStateToProps(state) { | function mapStateToProps(state) { | ||||||
| 	return { | 	return { | ||||||
| 		user: state.user | 		user: state.user, | ||||||
|  | 		currencies: state.securities.currency_list | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| var connect = require('react-redux').connect; | var connect = require('react-redux').connect; | ||||||
|  |  | ||||||
| var UserActions = require('../actions/UserActions'); | var UserActions = require('../actions/UserActions'); | ||||||
|  | var SecurityTemplateActions = require('../actions/SecurityTemplateActions'); | ||||||
|  |  | ||||||
| var MoneyGoApp = require('../components/MoneyGoApp'); | var MoneyGoApp = require('../components/MoneyGoApp'); | ||||||
|  |  | ||||||
| @@ -13,6 +14,7 @@ function mapStateToProps(state) { | |||||||
| function mapDispatchToProps(dispatch) { | function mapDispatchToProps(dispatch) { | ||||||
| 	return { | 	return { | ||||||
| 		tryResumingSession: function() {dispatch(UserActions.tryResumingSession())}, | 		tryResumingSession: function() {dispatch(UserActions.tryResumingSession())}, | ||||||
|  | 		fetchCurrencies: function() {dispatch(SecurityTemplateActions.fetchCurrencies())}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,9 @@ var UserActions = require('../actions/UserActions'); | |||||||
| var NewUserModal = require('../components/NewUserModal'); | var NewUserModal = require('../components/NewUserModal'); | ||||||
|  |  | ||||||
| function mapStateToProps(state) { | function mapStateToProps(state) { | ||||||
| 	return {} | 	return { | ||||||
|  | 		currencies: state.securityTemplates.currencies | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| function mapDispatchToProps(dispatch) { | function mapDispatchToProps(dispatch) { | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ function getJSONObj(json_input) { | |||||||
| class User { | class User { | ||||||
| 	constructor() { | 	constructor() { | ||||||
| 		this.UserId = -1; | 		this.UserId = -1; | ||||||
|  | 		this.DefaultCurrency = -1; | ||||||
| 		this.Name = ""; | 		this.Name = ""; | ||||||
| 		this.Username = ""; | 		this.Username = ""; | ||||||
| 		this.Password = ""; | 		this.Password = ""; | ||||||
| @@ -21,6 +22,7 @@ class User { | |||||||
| 	toJSON() { | 	toJSON() { | ||||||
| 		var json_obj = {}; | 		var json_obj = {}; | ||||||
| 		json_obj.UserId = this.UserId; | 		json_obj.UserId = this.UserId; | ||||||
|  | 		json_obj.DefaultCurrency = this.DefaultCurrency; | ||||||
| 		json_obj.Name = this.Name; | 		json_obj.Name = this.Name; | ||||||
| 		json_obj.Username = this.Username; | 		json_obj.Username = this.Username; | ||||||
| 		json_obj.Password = this.Password; | 		json_obj.Password = this.Password; | ||||||
| @@ -32,6 +34,8 @@ class User { | |||||||
|  |  | ||||||
| 		if (json_obj.hasOwnProperty("UserId")) | 		if (json_obj.hasOwnProperty("UserId")) | ||||||
| 			this.UserId = json_obj.UserId; | 			this.UserId = json_obj.UserId; | ||||||
|  | 		if (json_obj.hasOwnProperty("DefaultCurrency")) | ||||||
|  | 			this.DefaultCurrency = json_obj.DefaultCurrency; | ||||||
| 		if (json_obj.hasOwnProperty("Name")) | 		if (json_obj.hasOwnProperty("Name")) | ||||||
| 			this.Name = json_obj.Name; | 			this.Name = json_obj.Name; | ||||||
| 		if (json_obj.hasOwnProperty("Username")) | 		if (json_obj.hasOwnProperty("Username")) | ||||||
|   | |||||||
| @@ -3,30 +3,37 @@ var assign = require('object-assign'); | |||||||
| var SecurityTemplateConstants = require('../constants/SecurityTemplateConstants'); | var SecurityTemplateConstants = require('../constants/SecurityTemplateConstants'); | ||||||
| var UserConstants = require('../constants/UserConstants'); | var UserConstants = require('../constants/UserConstants'); | ||||||
|  |  | ||||||
| var SecurityType = require('../models').SecurityType; | const initialState = { | ||||||
|  | 	search: "", | ||||||
|  | 	type: 0, | ||||||
|  | 	templates: [], | ||||||
|  | 	currencies: [] | ||||||
|  | }; | ||||||
|  |  | ||||||
| module.exports = function(state = {search: "", type: 0, templates: [], searchNumber: 0}, action) { | module.exports = function(state = initialState, action) { | ||||||
| 	switch (action.type) { | 	switch (action.type) { | ||||||
| 		case SecurityTemplateConstants.SEARCH_SECURITY_TEMPLATES: | 		case SecurityTemplateConstants.SEARCH_SECURITY_TEMPLATES: | ||||||
| 			return { | 			return assign({}, state, { | ||||||
| 				search: action.searchString, | 				search: action.searchString, | ||||||
| 				type: action.searchType, | 				type: action.searchType, | ||||||
| 				templates: [] | 				templates: [] | ||||||
| 			}; | 			}); | ||||||
| 		case SecurityTemplateConstants.SECURITY_TEMPLATES_SEARCHED: | 		case SecurityTemplateConstants.SECURITY_TEMPLATES_SEARCHED: | ||||||
| 			if ((action.searchString != state.search) || (action.searchType != state.type)) | 			if ((action.searchString != state.search) || (action.searchType != state.type)) | ||||||
| 				return state; | 				return state; | ||||||
| 			return { | 			return assign({}, state, { | ||||||
| 				search: action.searchString, | 				search: action.searchString, | ||||||
| 				type: action.searchType, | 				type: action.searchType, | ||||||
| 				templates: action.securities | 				templates: action.securities | ||||||
| 			}; | 			}); | ||||||
|  | 		case SecurityTemplateConstants.CURRENCIES_FETCHED: | ||||||
|  | 			return assign({}, state, { | ||||||
|  | 				currencies: action.currencies | ||||||
|  | 			}); | ||||||
| 		case UserConstants.USER_LOGGEDOUT: | 		case UserConstants.USER_LOGGEDOUT: | ||||||
| 			return { | 			return assign({}, initialState, { | ||||||
| 				search: "", | 				currencies: state.currencies | ||||||
| 				type: 0, | 			}); | ||||||
| 				templates: [] |  | ||||||
| 			}; |  | ||||||
| 		default: | 		default: | ||||||
| 			return state; | 			return state; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -36,7 +36,7 @@ type Security struct { | |||||||
| 	// security is precise to | 	// security is precise to | ||||||
| 	Precision int | 	Precision int | ||||||
| 	Type      int64 | 	Type      int64 | ||||||
| 	// AlternateId is CUSIP for Type=Stock | 	// AlternateId is CUSIP for Type=Stock, ISO4217 for Type=Currency | ||||||
| 	AlternateId string | 	AlternateId string | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -86,6 +86,16 @@ func FindSecurityTemplate(name string, _type int64) *Security { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func FindCurrencyTemplate(iso4217 int64) *Security { | ||||||
|  | 	iso4217string := strconv.FormatInt(iso4217, 10) | ||||||
|  | 	for _, security := range SecurityTemplates { | ||||||
|  | 		if security.Type == Currency && security.AlternateId == iso4217string { | ||||||
|  | 			return &security | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func GetSecurity(securityid int64, userid int64) (*Security, error) { | func GetSecurity(securityid int64, userid int64) (*Security, error) { | ||||||
| 	var s Security | 	var s Security | ||||||
|  |  | ||||||
| @@ -171,6 +181,15 @@ func DeleteSecurity(s *Security) error { | |||||||
| 		return errors.New("One or more accounts still use this security") | 		return errors.New("One or more accounts still use this security") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	user, err := GetUserTx(transaction, s.UserId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return err | ||||||
|  | 	} else if user.DefaultCurrency == s.SecurityId { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return errors.New("Cannot delete security which is user's default currency") | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	count, err := transaction.Delete(s) | 	count, err := transaction.Delete(s) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		transaction.Rollback() | 		transaction.Rollback() | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								users.go
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								users.go
									
									
									
									
									
								
							| @@ -3,7 +3,9 @@ package main | |||||||
| import ( | import ( | ||||||
| 	"crypto/sha256" | 	"crypto/sha256" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"gopkg.in/gorp.v1" | ||||||
| 	"io" | 	"io" | ||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -11,12 +13,13 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| type User struct { | type User struct { | ||||||
| 	UserId       int64 | 	UserId          int64 | ||||||
| 	Name         string | 	DefaultCurrency int64 // SecurityId of default currency, or ISO4217 code for it if creating new user | ||||||
| 	Username     string | 	Name            string | ||||||
| 	Password     string `db:"-"` | 	Username        string | ||||||
| 	PasswordHash string `json:"-"` | 	Password        string `db:"-"` | ||||||
| 	Email        string | 	PasswordHash    string `json:"-"` | ||||||
|  | 	Email           string | ||||||
| } | } | ||||||
|  |  | ||||||
| const BogusPassword = "password" | const BogusPassword = "password" | ||||||
| @@ -54,6 +57,16 @@ func GetUser(userid int64) (*User, error) { | |||||||
| 	return &u, nil | 	return &u, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func GetUserTx(transaction *gorp.Transaction, userid int64) (*User, error) { | ||||||
|  | 	var u User | ||||||
|  |  | ||||||
|  | 	err := transaction.SelectOne(&u, "SELECT * from users where UserId=?", userid) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &u, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func GetUserByUsername(username string) (*User, error) { | func GetUserByUsername(username string) (*User, error) { | ||||||
| 	var u User | 	var u User | ||||||
|  |  | ||||||
| @@ -70,6 +83,12 @@ func InsertUser(u *User) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	security_template := FindCurrencyTemplate(u.DefaultCurrency) | ||||||
|  | 	if security_template == nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return errors.New("Invalid ISO4217 Default Currency") | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	existing, err := transaction.SelectInt("SELECT count(*) from users where Username=?", u.Username) | 	existing, err := transaction.SelectInt("SELECT count(*) from users where Username=?", u.Username) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		transaction.Rollback() | 		transaction.Rollback() | ||||||
| @@ -86,6 +105,28 @@ func InsertUser(u *User) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// Copy the security template and give it our new UserId | ||||||
|  | 	var security Security | ||||||
|  | 	security = *security_template | ||||||
|  | 	security.UserId = u.UserId | ||||||
|  |  | ||||||
|  | 	err = InsertSecurityTx(transaction, &security) | ||||||
|  | 	if err != nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Update the user's DefaultCurrency to our new SecurityId | ||||||
|  | 	u.DefaultCurrency = security.SecurityId | ||||||
|  | 	count, err := transaction.Update(u) | ||||||
|  | 	if err != nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return err | ||||||
|  | 	} else if count != 1 { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return errors.New("Would have updated more than one user") | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	err = transaction.Commit() | 	err = transaction.Commit() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		transaction.Rollback() | 		transaction.Rollback() | ||||||
| @@ -103,6 +144,42 @@ func GetUserFromSession(r *http.Request) (*User, error) { | |||||||
| 	return GetUser(s.UserId) | 	return GetUser(s.UserId) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func UpdateUser(u *User) error { | ||||||
|  | 	transaction, err := DB.Begin() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	security, err := GetSecurityTx(transaction, u.DefaultCurrency, u.UserId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return err | ||||||
|  | 	} else if security.UserId != u.UserId || security.SecurityId != u.DefaultCurrency { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return errors.New("UserId and DefaultCurrency don't match the fetched security") | ||||||
|  | 	} else if security.Type != Currency { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return errors.New("New DefaultCurrency security is not a currency") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	count, err := transaction.Update(u) | ||||||
|  | 	if err != nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return err | ||||||
|  | 	} else if count != 1 { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return errors.New("Would have updated more than one user") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = transaction.Commit() | ||||||
|  | 	if err != nil { | ||||||
|  | 		transaction.Rollback() | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func UserHandler(w http.ResponseWriter, r *http.Request) { | func UserHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 	if r.Method == "POST" { | 	if r.Method == "POST" { | ||||||
| 		user_json := r.PostFormValue("user") | 		user_json := r.PostFormValue("user") | ||||||
| @@ -187,8 +264,8 @@ func UserHandler(w http.ResponseWriter, r *http.Request) { | |||||||
| 				user.PasswordHash = old_pwhash | 				user.PasswordHash = old_pwhash | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			count, err := DB.Update(user) | 			err = UpdateUser(user) | ||||||
| 			if count != 1 || err != nil { | 			if err != nil { | ||||||
| 				WriteError(w, 999 /*Internal Error*/) | 				WriteError(w, 999 /*Internal Error*/) | ||||||
| 				log.Print(err) | 				log.Print(err) | ||||||
| 				return | 				return | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user