package main import ( "encoding/json" "errors" "fmt" "log" "net/http" "net/url" "strconv" "strings" ) const ( Currency int64 = 1 Stock = 2 ) func GetSecurityType(typestring string) int64 { if strings.EqualFold(typestring, "currency") { return Currency } else if strings.EqualFold(typestring, "stock") { return Stock } else { return 0 } } type Security struct { SecurityId int64 UserId int64 Name string Description string Symbol string // Number of decimal digits (to the right of the decimal point) this // security is precise to Precision int Type int64 // AlternateId is CUSIP for Type=Stock AlternateId string } type SecurityList struct { Securities *[]*Security `json:"securities"` } func (s *Security) Read(json_str string) error { dec := json.NewDecoder(strings.NewReader(json_str)) return dec.Decode(s) } func (s *Security) Write(w http.ResponseWriter) error { enc := json.NewEncoder(w) return enc.Encode(s) } func (sl *SecurityList) Write(w http.ResponseWriter) error { enc := json.NewEncoder(w) return enc.Encode(sl) } func SearchSecurityTemplates(search string, _type int64, limit int64) []*Security { upperSearch := strings.ToUpper(search) var results []*Security for i, security := range SecurityTemplates { if strings.Contains(strings.ToUpper(security.Name), upperSearch) || strings.Contains(strings.ToUpper(security.Description), upperSearch) || strings.Contains(strings.ToUpper(security.Symbol), upperSearch) { if _type == 0 || _type == security.Type { results = append(results, &SecurityTemplates[i]) if limit != -1 && int64(len(results)) >= limit { break } } } } return results } func GetSecurity(securityid int64, userid int64) (*Security, error) { var s Security err := DB.SelectOne(&s, "SELECT * from securities where UserId=? AND SecurityId=?", userid, securityid) if err != nil { return nil, err } return &s, nil } func GetSecurities(userid int64) (*[]*Security, error) { var securities []*Security _, err := DB.Select(&securities, "SELECT * from securities where UserId=?", userid) if err != nil { return nil, err } return &securities, nil } func InsertSecurity(s *Security) error { err := DB.Insert(s) if err != nil { return err } return nil } func UpdateSecurity(s *Security) error { transaction, err := DB.Begin() if err != nil { return err } count, err := transaction.Update(s) if err != nil { transaction.Rollback() return err } if count != 1 { transaction.Rollback() return errors.New("Updated more than one security") } err = transaction.Commit() if err != nil { transaction.Rollback() return err } return nil } func DeleteSecurity(s *Security) error { transaction, err := DB.Begin() if err != nil { return err } // First, ensure no accounts are using this security accounts, err := transaction.SelectInt("SELECT count(*) from accounts where UserId=? and SecurityId=?", s.UserId, s.SecurityId) if accounts != 0 { transaction.Rollback() return errors.New("One or more accounts still use this security") } count, err := transaction.Delete(s) if err != nil { transaction.Rollback() return err } if count != 1 { transaction.Rollback() return errors.New("Deleted more than one security") } err = transaction.Commit() if err != nil { transaction.Rollback() return err } return nil } func GetSecurityByName(name string) (*Security, error) { return nil, fmt.Errorf("unimplemented") } func GetSecurityByNameAndType(name string, _type int64) (*Security, error) { return nil, fmt.Errorf("unimplemented") } func SecurityHandler(w http.ResponseWriter, r *http.Request) { user, err := GetUserFromSession(r) if err != nil { WriteError(w, 1 /*Not Signed In*/) return } if r.Method == "POST" { security_json := r.PostFormValue("security") if security_json == "" { WriteError(w, 3 /*Invalid Request*/) return } var security Security err := security.Read(security_json) if err != nil { WriteError(w, 3 /*Invalid Request*/) return } security.SecurityId = -1 security.UserId = user.UserId err = InsertSecurity(&security) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } w.WriteHeader(201 /*Created*/) err = security.Write(w) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } } else if r.Method == "GET" { var securityid int64 n, err := GetURLPieces(r.URL.Path, "/security/%d", &securityid) if err != nil || n != 1 { //Return all securities var sl SecurityList securities, err := GetSecurities(user.UserId) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } sl.Securities = securities err = (&sl).Write(w) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } } else { security, err := GetSecurity(securityid, user.UserId) if err != nil { WriteError(w, 3 /*Invalid Request*/) return } err = security.Write(w) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } } } else { securityid, err := GetURLID(r.URL.Path) if err != nil { WriteError(w, 3 /*Invalid Request*/) return } if r.Method == "PUT" { security_json := r.PostFormValue("security") if security_json == "" { WriteError(w, 3 /*Invalid Request*/) return } var security Security err := security.Read(security_json) if err != nil || security.SecurityId != securityid { WriteError(w, 3 /*Invalid Request*/) return } security.UserId = user.UserId err = UpdateSecurity(&security) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } err = security.Write(w) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } } else if r.Method == "DELETE" { security, err := GetSecurity(securityid, user.UserId) if err != nil { WriteError(w, 3 /*Invalid Request*/) return } err = DeleteSecurity(security) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } WriteSuccess(w) } } } func SecurityTemplateHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { var sl SecurityList query, _ := url.ParseQuery(r.URL.RawQuery) var limit int64 = -1 search := query.Get("search") _type := GetSecurityType(query.Get("type")) limitstring := query.Get("limit") if limitstring != "" { limitint, err := strconv.ParseInt(limitstring, 10, 0) if err != nil { WriteError(w, 3 /*Invalid Request*/) return } limit = limitint } securities := SearchSecurityTemplates(search, _type, limit) sl.Securities = &securities err := (&sl).Write(w) if err != nil { WriteError(w, 999 /*Internal Error*/) log.Print(err) return } } else { WriteError(w, 3 /*Invalid Request*/) } }