2017-10-04 19:35:59 -04:00
package handlers
2015-06-25 22:36:58 -04:00
import (
"crypto/sha256"
"encoding/json"
2017-06-21 21:25:38 -04:00
"errors"
2015-06-25 22:36:58 -04:00
"fmt"
"io"
"log"
"net/http"
"strings"
)
type User struct {
2017-06-21 21:25:38 -04:00
UserId int64
DefaultCurrency int64 // SecurityId of default currency, or ISO4217 code for it if creating new user
Name string
Username string
Password string ` db:"-" `
PasswordHash string ` json:"-" `
Email string
2015-06-25 22:36:58 -04:00
}
const BogusPassword = "password"
type UserExistsError struct { }
func ( ueu UserExistsError ) Error ( ) string {
return "User exists"
}
func ( u * User ) Write ( w http . ResponseWriter ) error {
enc := json . NewEncoder ( w )
return enc . Encode ( u )
}
func ( u * User ) Read ( json_str string ) error {
dec := json . NewDecoder ( strings . NewReader ( json_str ) )
return dec . Decode ( u )
}
func ( u * User ) HashPassword ( ) {
password_hasher := sha256 . New ( )
io . WriteString ( password_hasher , u . Password )
u . PasswordHash = fmt . Sprintf ( "%x" , password_hasher . Sum ( nil ) )
u . Password = ""
}
2017-10-14 14:20:50 -04:00
func GetUser ( tx * Tx , userid int64 ) ( * User , error ) {
2015-06-25 22:36:58 -04:00
var u User
2017-10-14 14:20:50 -04:00
err := tx . SelectOne ( & u , "SELECT * from users where UserId=?" , userid )
2015-06-25 22:36:58 -04:00
if err != nil {
return nil , err
}
return & u , nil
}
2017-10-14 14:20:50 -04:00
func GetUserByUsername ( tx * Tx , username string ) ( * User , error ) {
2015-06-25 22:36:58 -04:00
var u User
2017-10-14 14:20:50 -04:00
err := tx . SelectOne ( & u , "SELECT * from users where Username=?" , username )
2015-06-25 22:36:58 -04:00
if err != nil {
return nil , err
}
return & u , nil
}
2017-10-14 14:20:50 -04:00
func InsertUser ( tx * Tx , u * User ) error {
2017-06-21 21:25:38 -04:00
security_template := FindCurrencyTemplate ( u . DefaultCurrency )
if security_template == nil {
return errors . New ( "Invalid ISO4217 Default Currency" )
}
2017-10-14 14:20:50 -04:00
existing , err := tx . SelectInt ( "SELECT count(*) from users where Username=?" , u . Username )
2015-06-25 22:36:58 -04:00
if err != nil {
return err
}
if existing > 0 {
return UserExistsError { }
}
2017-10-14 14:20:50 -04:00
err = tx . Insert ( u )
2015-06-25 22:36:58 -04:00
if err != nil {
return err
}
2017-06-21 21:25:38 -04:00
// Copy the security template and give it our new UserId
var security Security
security = * security_template
security . UserId = u . UserId
2017-10-14 19:41:13 -04:00
err = InsertSecurity ( tx , & security )
2017-06-21 21:25:38 -04:00
if err != nil {
return err
}
// Update the user's DefaultCurrency to our new SecurityId
u . DefaultCurrency = security . SecurityId
2017-10-14 14:20:50 -04:00
count , err := tx . Update ( u )
2017-06-21 21:25:38 -04:00
if err != nil {
return err
} else if count != 1 {
return errors . New ( "Would have updated more than one user" )
}
2015-06-25 22:36:58 -04:00
return nil
}
2017-10-14 14:20:50 -04:00
func GetUserFromSession ( tx * Tx , r * http . Request ) ( * User , error ) {
s , err := GetSession ( tx , r )
2015-06-25 22:36:58 -04:00
if err != nil {
return nil , err
}
2017-10-14 14:20:50 -04:00
return GetUser ( tx , s . UserId )
2015-06-25 22:36:58 -04:00
}
2017-10-14 14:20:50 -04:00
func UpdateUser ( tx * Tx , u * User ) error {
2017-10-14 19:41:13 -04:00
security , err := GetSecurity ( tx , u . DefaultCurrency , u . UserId )
2017-06-21 21:25:38 -04:00
if err != nil {
return err
} else if security . UserId != u . UserId || security . SecurityId != u . DefaultCurrency {
return errors . New ( "UserId and DefaultCurrency don't match the fetched security" )
} else if security . Type != Currency {
return errors . New ( "New DefaultCurrency security is not a currency" )
}
2017-10-14 14:20:50 -04:00
count , err := tx . Update ( u )
2017-06-21 21:25:38 -04:00
if err != nil {
return err
} else if count != 1 {
return errors . New ( "Would have updated more than one user" )
}
return nil
}
2017-10-14 14:20:50 -04:00
func DeleteUser ( tx * Tx , u * User ) error {
count , err := tx . Delete ( u )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
if count != 1 {
return fmt . Errorf ( "No user to delete" )
}
2017-10-24 20:13:42 -04:00
_ , err = tx . Exec ( "DELETE FROM prices WHERE prices.SecurityId IN (SELECT securities.SecurityId FROM securities WHERE securities.UserId=?)" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
2017-10-24 20:13:42 -04:00
_ , err = tx . Exec ( "DELETE FROM splits WHERE splits.TransactionId IN (SELECT transactions.TransactionId FROM transactions WHERE transactions.UserId=?)" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
2017-10-14 14:20:50 -04:00
_ , err = tx . Exec ( "DELETE FROM transactions WHERE transactions.UserId=?" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
2017-10-14 14:20:50 -04:00
_ , err = tx . Exec ( "DELETE FROM securities WHERE securities.UserId=?" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
2017-10-14 14:20:50 -04:00
_ , err = tx . Exec ( "DELETE FROM accounts WHERE accounts.UserId=?" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
2017-10-14 14:20:50 -04:00
_ , err = tx . Exec ( "DELETE FROM reports WHERE reports.UserId=?" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
2017-10-14 14:20:50 -04:00
_ , err = tx . Exec ( "DELETE FROM sessions WHERE sessions.UserId=?" , u . UserId )
2017-10-07 21:04:59 -04:00
if err != nil {
return err
}
return nil
}
2017-11-12 20:17:27 -05:00
func UserHandler ( r * http . Request , context * Context ) ResponseWriterWriter {
2015-06-25 22:36:58 -04:00
if r . Method == "POST" {
var user User
2017-11-13 20:48:19 -05:00
if err := ReadJSON ( r , & user ) ; err != nil {
2017-10-14 14:20:50 -04:00
return NewError ( 3 /*Invalid Request*/ )
2015-06-25 22:36:58 -04:00
}
user . UserId = - 1
user . HashPassword ( )
2017-11-13 20:48:19 -05:00
err := InsertUser ( context . Tx , & user )
2015-06-25 22:36:58 -04:00
if err != nil {
if _ , ok := err . ( UserExistsError ) ; ok {
2017-10-14 14:20:50 -04:00
return NewError ( 4 /*User Exists*/ )
2015-06-25 22:36:58 -04:00
} else {
log . Print ( err )
2017-10-14 14:20:50 -04:00
return NewError ( 999 /*Internal Error*/ )
2015-06-25 22:36:58 -04:00
}
}
2017-10-14 14:20:50 -04:00
return ResponseWrapper { 201 , & user }
2015-06-25 22:36:58 -04:00
} else {
2017-11-12 20:17:27 -05:00
user , err := GetUserFromSession ( context . Tx , r )
2015-06-25 22:36:58 -04:00
if err != nil {
2017-10-14 14:20:50 -04:00
return NewError ( 1 /*Not Signed In*/ )
2015-06-25 22:36:58 -04:00
}
2017-11-12 21:12:49 -05:00
userid , err := context . NextID ( )
2015-06-25 22:36:58 -04:00
if err != nil {
2017-10-14 14:20:50 -04:00
return NewError ( 3 /*Invalid Request*/ )
2015-06-25 22:36:58 -04:00
}
if userid != user . UserId {
2017-10-14 14:20:50 -04:00
return NewError ( 2 /*Unauthorized Access*/ )
2015-06-25 22:36:58 -04:00
}
if r . Method == "GET" {
2017-10-14 14:20:50 -04:00
return user
2015-06-25 22:36:58 -04:00
} else if r . Method == "PUT" {
// Save old PWHash in case the new password is bogus
old_pwhash := user . PasswordHash
2017-11-13 20:48:19 -05:00
if err := ReadJSON ( r , & user ) ; err != nil || user . UserId != userid {
2017-10-14 14:20:50 -04:00
return NewError ( 3 /*Invalid Request*/ )
2015-06-25 22:36:58 -04:00
}
// If the user didn't create a new password, keep their old one
if user . Password != BogusPassword {
user . HashPassword ( )
} else {
user . Password = ""
user . PasswordHash = old_pwhash
}
2017-11-12 20:17:27 -05:00
err = UpdateUser ( context . Tx , user )
2017-06-21 21:25:38 -04:00
if err != nil {
2015-06-25 22:36:58 -04:00
log . Print ( err )
2017-10-14 14:20:50 -04:00
return NewError ( 999 /*Internal Error*/ )
2015-06-25 22:36:58 -04:00
}
2017-10-14 14:20:50 -04:00
return user
2015-06-25 22:36:58 -04:00
} else if r . Method == "DELETE" {
2017-11-12 20:17:27 -05:00
err := DeleteUser ( context . Tx , user )
2017-10-07 21:04:59 -04:00
if err != nil {
2015-06-25 22:36:58 -04:00
log . Print ( err )
2017-10-14 14:20:50 -04:00
return NewError ( 999 /*Internal Error*/ )
2015-06-25 22:36:58 -04:00
}
2017-10-14 14:20:50 -04:00
return SuccessWriter { }
2015-06-25 22:36:58 -04:00
}
}
2017-10-14 14:20:50 -04:00
return NewError ( 3 /*Invalid Request*/ )
2015-06-25 22:36:58 -04:00
}