diff options
-rw-r--r-- | auth_persona.go | 56 | ||||
-rw-r--r-- | core.go | 26 | ||||
-rw-r--r-- | core_test.go | 4 | ||||
-rw-r--r-- | formats.go | 10 | ||||
-rw-r--r-- | octopart.go | 277 | ||||
-rw-r--r-- | octopart_test.go | 87 | ||||
-rw-r--r-- | serve.go | 245 |
7 files changed, 374 insertions, 331 deletions
diff --git a/auth_persona.go b/auth_persona.go index 7895c2d..2b5942e 100644 --- a/auth_persona.go +++ b/auth_persona.go @@ -1,52 +1,52 @@ package main import ( - "encoding/json" - "io" - "io/ioutil" - "log" - "net/http" - "net/url" + "encoding/json" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" ) type PersonaResponse struct { - Status, Email, Reason string + Status, Email, Reason string } func (b PersonaResponse) Okay() bool { - return b.Status == "okay" + return b.Status == "okay" } func VerifyPersonaAssertion(assertion, audience string) PersonaResponse { - resp, _ := http.PostForm( - "https://browserid.org/verify", - url.Values{ - "assertion": {assertion}, - "audience": {audience}, - }) - response := personaResponseFromJson(resp.Body) - resp.Body.Close() - - return response + resp, _ := http.PostForm( + "https://browserid.org/verify", + url.Values{ + "assertion": {assertion}, + "audience": {audience}, + }) + response := personaResponseFromJson(resp.Body) + resp.Body.Close() + + return response } func personaResponseFromJson(r io.Reader) (resp PersonaResponse) { - body, err := ioutil.ReadAll(r) + body, err := ioutil.ReadAll(r) - if err != nil { - log.Fatal(err) - } + if err != nil { + log.Fatal(err) + } - err = json.Unmarshal(body, &resp) + err = json.Unmarshal(body, &resp) - if err != nil { - log.Fatal(err) - } + if err != nil { + log.Fatal(err) + } - return resp + return resp } -type PersonaAuth bool +type PersonaAuth bool func (pa PersonaAuth) CheckLogin(name, pw string) error { return nil @@ -15,22 +15,22 @@ type Offer struct { Sku string `json:"sku"` Url string `json:"distributor_url"` Comment string `json:"comment"` - Available uint32 `json:"avail"` + Available uint32 `json:"avail"` Prices []OfferPrice `json:"prices"` } type LineItem struct { - Manufacturer string `json:"manufacturer"` - Mpn string `json:"mpn"` - Description string `json:"description"` - FormFactor string `json:"form_factor"` // type:string - Specs string `json:"specs"` // comma seperated list - Comment string `json:"comment"` - Tag string `json:"tag"` // comma seperated list - Category string `json:"category"` // hierarchy as comma seperated list - Elements []string `json:"elements"` - Offers []Offer `json:"offers"` - AggregateInfo map[string]string `json:"miscinfo"` + Manufacturer string `json:"manufacturer"` + Mpn string `json:"mpn"` + Description string `json:"description"` + FormFactor string `json:"form_factor"` // type:string + Specs string `json:"specs"` // comma seperated list + Comment string `json:"comment"` + Tag string `json:"tag"` // comma seperated list + Category string `json:"category"` // hierarchy as comma seperated list + Elements []string `json:"elements"` + Offers []Offer `json:"offers"` + AggregateInfo map[string]string `json:"miscinfo"` } func (li *LineItem) Id() string { @@ -117,6 +117,6 @@ func makeTestBom() (*BomMeta, *Bom) { b.AddLineItem(&li) b.AddLineItem(&li) b.AddLineItem(&li) - bm := &BomMeta{Name: "Some Bom", Owner: "Some Owner", Description: "This is such a thing!", HeadVersion: b.Version, Homepage: "http://bommom.com", IsPublicView: true, IsPublicEdit: false} + bm := &BomMeta{Name: "Some Bom", Owner: "Some Owner", Description: "This is such a thing!", HeadVersion: b.Version, Homepage: "http://bommom.com", IsPublicView: true, IsPublicEdit: false} return bm, b } diff --git a/core_test.go b/core_test.go index b89e23f..d1905cb 100644 --- a/core_test.go +++ b/core_test.go @@ -8,7 +8,7 @@ import ( ) func TestNewBom(t *testing.T) { - b := makeTestBom() + b, _ := makeTestBom() if b == nil { t.Errorf("Something went wrong") } @@ -16,7 +16,7 @@ func TestNewBom(t *testing.T) { func TestBomJSONDump(t *testing.T) { - b := makeTestBom() + b, _ := makeTestBom() enc := json.NewEncoder(os.Stdout) if err := enc.Encode(b); err != nil { @@ -100,8 +100,8 @@ func LoadBomFromCSV(input io.Reader) (*Bom, error) { header, err := reader.Read() if err != nil { - log.Printf("error parsing .csv: %s", err) - return nil, err + log.Printf("error parsing .csv: %s", err) + return nil, err } var li *LineItem var el_count int @@ -151,9 +151,9 @@ func LoadBomFromCSV(input io.Reader) (*Bom, error) { el_count = len(li.Elements) // XXX: kludge if n > 99999 || el_count > 99999 { - err = Error("too large a quantity of elements passed") - log.Printf("error parsing .csv: %s", err) - return nil, err + err = Error("too large a quantity of elements passed") + log.Printf("error parsing .csv: %s", err) + return nil, err } else if el_count > n { if *verbose { log.Println("more symbols than qty, taking all symbols") diff --git a/octopart.go b/octopart.go index 367bc99..654c03d 100644 --- a/octopart.go +++ b/octopart.go @@ -1,12 +1,12 @@ package main import ( - "net/http" - "net/url" - "encoding/json" - "bytes" - "log" - //"io/ioutil" + "bytes" + "encoding/json" + "log" + "net/http" + "net/url" + //"io/ioutil" ) /* @@ -17,143 +17,176 @@ LineItems. var pricingSource *OctopartClient type OctopartClient struct { - ApiKey string - RemoteHost string - client *http.Client - infoCache map[string]interface{} + ApiKey string + RemoteHost string + client *http.Client + infoCache map[string]interface{} } func NewOctopartClient(apikey string) *OctopartClient { - oc := &OctopartClient{ApiKey: apikey, - RemoteHost: "https://octopart.com"} - oc.client = &http.Client{} - oc.infoCache = make(map[string]interface{}) - return oc + oc := &OctopartClient{ApiKey: apikey, + RemoteHost: "https://octopart.com"} + oc.client = &http.Client{} + oc.infoCache = make(map[string]interface{}) + return oc } func openPricingSource() { - // TODO: pass through octopart API key here - pricingSource = NewOctopartClient("") + // TODO: pass through octopart API key here + pricingSource = NewOctopartClient("") } func (oc *OctopartClient) apiCall(method string, params map[string]string) (map[string]interface{}, error) { - paramString := "?apikey=" + oc.ApiKey - // TODO: assert clean-ness of params - // TODO: use url.Values instead... - for key := range params { - paramString += "&" + url.QueryEscape(key) + "=" + url.QueryEscape(params[key]) - } - paramStringUnescaped, _ := url.QueryUnescape(paramString) // TODO: err - log.Println("Fetching: " + oc.RemoteHost + "/api/v2/" + method + paramStringUnescaped) - resp, err := oc.client.Get(oc.RemoteHost + "/api/v2/" + method + paramString) - if err != nil { - return nil, err - } - if resp.StatusCode != 200 { - return nil, Error("Octopart API call error: " + resp.Status) - } - result := make(map[string]interface{}) - defer resp.Body.Close() - //body, err := ioutil.ReadAll(resp.Body) - //if err != nil { - // return nil, err - //} - //body = append(body, '\n') - //dec := json.NewDecoder(bytes.NewReader(body)) - dec := json.NewDecoder(resp.Body) - if err = dec.Decode(&result); err != nil { - return nil, err - } - return result, nil + paramString := "?apikey=" + oc.ApiKey + // TODO: assert clean-ness of params + // TODO: use url.Values instead... + for key := range params { + paramString += "&" + url.QueryEscape(key) + "=" + url.QueryEscape(params[key]) + } + paramStringUnescaped, _ := url.QueryUnescape(paramString) // TODO: err + log.Println("Fetching: " + oc.RemoteHost + "/api/v2/" + method + paramStringUnescaped) + resp, err := oc.client.Get(oc.RemoteHost + "/api/v2/" + method + paramString) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, Error("Octopart API call error: " + resp.Status) + } + result := make(map[string]interface{}) + defer resp.Body.Close() + //body, err := ioutil.ReadAll(resp.Body) + //if err != nil { + // return nil, err + //} + //body = append(body, '\n') + //dec := json.NewDecoder(bytes.NewReader(body)) + dec := json.NewDecoder(resp.Body) + if err = dec.Decode(&result); err != nil { + return nil, err + } + return result, nil } // this method doesn't check internal cache, but it does append to it func (oc *OctopartClient) bomApiCall(manufacturers, mpns []string) ([]map[string]interface{}, error) { - // TODO: check len(mpns) == len(manufacturers) - queryList := make([]map[string]string, len(mpns)) - listItem := make(map[string]string) - for i, _ := range mpns { - listItem = make(map[string]string) - listItem["mpn_or_sku"] = mpns[i] - listItem["manufacturer"] = manufacturers[i] - listItem["limit"] = "1" - listItem["reference"] = manufacturers[i] + "|" + mpns[i] - queryList[i] = listItem - } + // TODO: check len(mpns) == len(manufacturers) + queryList := make([]map[string]string, len(mpns)) + listItem := make(map[string]string) + for i, _ := range mpns { + listItem = make(map[string]string) + listItem["mpn_or_sku"] = mpns[i] + listItem["manufacturer"] = manufacturers[i] + listItem["limit"] = "1" + listItem["reference"] = manufacturers[i] + "|" + mpns[i] + queryList[i] = listItem + } - linesBuffer := new(bytes.Buffer) - enc := json.NewEncoder(linesBuffer) - if err := enc.Encode(queryList); err != nil { - return nil, err - } + linesBuffer := new(bytes.Buffer) + enc := json.NewEncoder(linesBuffer) + if err := enc.Encode(queryList); err != nil { + return nil, err + } - response, err := oc.apiCall("bom/match", map[string]string{"lines": linesBuffer.String()}) - if err != nil { - return nil, err - } - // TODO: just grabbing first result for now; user can make better specification later - ret := make([]map[string]interface{}, len(mpns)) - for i, rawresult := range response["results"].([]interface{}) { - result := rawresult.(map[string]interface{}) - hits := int(result["hits"].(float64)) - reference := result["reference"].(string) - if hits == 0 { - ret[i] = nil - oc.infoCache[reference] = nil - } else { - ret[i] = result["items"].([]interface{})[0].(map[string]interface{}) - oc.infoCache[reference] = ret[i] - } - } - return ret, nil + response, err := oc.apiCall("bom/match", map[string]string{"lines": linesBuffer.String()}) + if err != nil { + return nil, err + } + // TODO: just grabbing first result for now; user can make better specification later + ret := make([]map[string]interface{}, len(mpns)) + for i, rawresult := range response["results"].([]interface{}) { + result := rawresult.(map[string]interface{}) + hits := int(result["hits"].(float64)) + reference := result["reference"].(string) + if hits == 0 { + ret[i] = nil + oc.infoCache[reference] = nil + } else { + ret[i] = result["items"].([]interface{})[0].(map[string]interface{}) + oc.infoCache[reference] = ret[i] + } + } + return ret, nil } -func (oc *OctopartClient) GetMarketInfo(manufacturers, mpns []string) ([]interface{}, error) { - if len(mpns) < 1 { - return nil, Error("no mpns strings passed in") - } - if len(mpns) != len(manufacturers) { - return nil, Error("number of mpns doesn't match number of manufacturers") - } - if len(mpns) > 100 { - return nil, Error("can't handle more than 100 queries at a time (yet)") - } - mpnToQuery := make([]string, 0) - manufacturersToQuery := make([]string, 0) - queryHash := "" - // check for queryHashes in internal cache - for i, _ := range mpns { - queryHash = manufacturers[i] + "|" + mpns[i] - if _, hasKey := oc.infoCache[queryHash]; hasKey != true { - manufacturersToQuery = append(manufacturersToQuery, manufacturers[i]) - mpnToQuery = append(mpnToQuery, mpns[i]) - } - } - // if necessary, fetch missing queryHashes to internal cache - if len(mpnToQuery) > 0 { - if _, err := oc.bomApiCall(manufacturersToQuery, mpnToQuery); err != nil { - return nil, err - } - } - // construct list of return info - result := make([]interface{}, len(mpns)) - for i, _ := range mpns { - queryHash = manufacturers[i] + "|" + mpns[i] - value, hasKey := oc.infoCache[queryHash] - if hasKey != true { - return nil, Error("key should be in cache, but isn't: " + queryHash) - } - result[i] = value - } - return result, nil +// this method checks the API query cache +func (oc *OctopartClient) GetMarketInfoList(manufacturers, mpns []string) ([]interface{}, error) { + if len(mpns) < 1 { + return nil, Error("no mpns strings passed in") + } + if len(mpns) != len(manufacturers) { + return nil, Error("number of mpns doesn't match number of manufacturers") + } + if len(mpns) > 100 { + return nil, Error("can't handle more than 100 queries at a time (yet)") + } + mpnToQuery := make([]string, 0) + manufacturersToQuery := make([]string, 0) + queryHash := "" + // check for queryHashes in internal cache + for i, _ := range mpns { + queryHash = manufacturers[i] + "|" + mpns[i] + if _, hasKey := oc.infoCache[queryHash]; hasKey != true { + manufacturersToQuery = append(manufacturersToQuery, manufacturers[i]) + mpnToQuery = append(mpnToQuery, mpns[i]) + } + } + // if necessary, fetch missing queryHashes remotely + if len(mpnToQuery) > 0 { + if _, err := oc.bomApiCall(manufacturersToQuery, mpnToQuery); err != nil { + return nil, err + } + } + // construct list of return info + result := make([]interface{}, len(mpns)) + for i, _ := range mpns { + queryHash = manufacturers[i] + "|" + mpns[i] + value, hasKey := oc.infoCache[queryHash] + if hasKey != true { + return nil, Error("key should be in cache, but isn't: " + queryHash) + } + result[i] = value + } + return result, nil } -func (oc *OctopartClient) GetReducedPricing(mpn, manufacturer string) (interface{}, error) { - marketInfo, err := oc.GetMarketInfo([]string{mpn}, []string{manufacturer}) +func (oc *OctopartClient) GetMarketInfo(manufacturer, mpn string) (map[string]interface{}, error) { + info, err := oc.GetMarketInfoList([]string{manufacturer}, []string{mpn}) if err != nil { return nil, err } - // reduce marketInfo to pricing - return marketInfo[0], nil + return info[0].(map[string]interface{}), nil +} + +func (oc *OctopartClient) GetExtraInfo(manufacturer, mpn string) (map[string]string, error) { + marketInfo, err := oc.GetMarketInfo(manufacturer, mpn) + if err != nil { + return nil, err + } + // extract market price, total avail, and "availability factor" from + // market info + log.Println(marketInfo) + ret := make(map[string]string) + ret["MarketPrice"] = marketInfo["avg_price"].(string) + ret["MarketFactor"] = marketInfo["market_availability"].(string) + ret["MarketTotalAvailable"] = marketInfo["total_avail"].(string) + return ret, nil } +func (oc *OctopartClient) AttachMarketInfo(li *LineItem) error { + if li.AggregateInfo == nil { + li.AggregateInfo = make(map[string]string) + } + extraInfo, err := oc.GetExtraInfo(li.Manufacturer, li.Mpn) + if err != nil { + log.Println(err.Error()) + return err + } + for key := range extraInfo { + li.AggregateInfo[key] = string(extraInfo[key]) + } + return nil +} + +func (oc *OctopartClient) AttachMarketInfoBom(b *Bom) error { + return nil +} diff --git a/octopart_test.go b/octopart_test.go index fdbd9b0..d2c8fbd 100644 --- a/octopart_test.go +++ b/octopart_test.go @@ -1,52 +1,63 @@ package main import ( + "log" + "os" "testing" - "log" ) func TestApiCall(t *testing.T) { - oc := NewOctopartClient("") - result, err := oc.apiCall("parts/search", map[string]string{"q": "ne555", "limit": "2"}) - if err != nil { - t.Errorf("Error with api call: " + err.Error()) - } - log.Println(result["hits"]) + oc := NewOctopartClient("") + result, err := oc.apiCall("parts/search", map[string]string{"q": "ne555", "limit": "2"}) + if err != nil { + t.Errorf("Error with api call: " + err.Error()) + } + log.Println(result["hits"]) } -func TestGetMarketInfo(t *testing.T) { - oc := NewOctopartClient("") - log.Println("Running the first time...") - result, err := oc.GetMarketInfo([]string{"ti", "atmel", "atmel"}, []string{"ne555", "attiny*", "avrtiny123qqq?"}) - if err != nil { - t.Errorf("Error with api call: " + err.Error()) - } - for i, r := range result { - if r == nil { - log.Printf("\t%d: %s", i, "nil") - } else { - log.Printf("\t%d: %s", i, r.(map[string]interface{})["detail_url"]) - } - } - log.Println("Running a second time, results should be cached...") - result, err = oc.GetMarketInfo([]string{"ti", "atmel", "atmel"}, []string{"ne555", "attiny*", "avrtiny123qqq?"}) - if err != nil { - t.Errorf("Error with api call: " + err.Error()) - } - for i, r := range result { - if r == nil { - log.Printf("\t%d: %s", i, "nil") - } else { - log.Printf("\t%d: %s", i, r.(map[string]interface{})["detail_url"]) - } +func TestGetMarketInfoList(t *testing.T) { + oc := NewOctopartClient("") + log.Println("Running the first time...") + result, err := oc.GetMarketInfoList([]string{"ti", "atmel", "atmel"}, []string{"ne555", "attiny*", "avrtiny123qqq?"}) + if err != nil { + t.Errorf("Error with api call: " + err.Error()) + } + for i, r := range result { + if r == nil { + log.Printf("\t%d: %s", i, "nil") + } else { + log.Printf("\t%d: %s", i, r.(map[string]interface{})["detail_url"]) + } + } + log.Println("Running a second time, results should be cached...") + result, err = oc.GetMarketInfoList([]string{"ti", "atmel", "atmel"}, []string{"ne555", "attiny*", "avrtiny123qqq?"}) + if err != nil { + t.Errorf("Error with api call: " + err.Error()) + } + for i, r := range result { + if r == nil { + log.Printf("\t%d: %s", i, "nil") + } else { + log.Printf("\t%d: %s", i, r.(map[string]interface{})["detail_url"]) + } + } + log.Println("Running in single mode, result should be cached...") + result_single, err := oc.GetMarketInfo("ti", "ne555") + if err != nil { + t.Errorf("Error with api call: " + err.Error()) + } + if result_single == nil { + log.Printf("\t%d: %s", "nil") + } else { + log.Printf("\t%d: %s", result_single["detail_url"]) } } func TestAttachInfo(t *testing.T) { - _, b := makeTestBom() - bm := &BomMeta{} - oc := NewOctopartClient("") - oc.AttachMarketInfo(oc) - DumpBomAsText(bm, b, os.Stdout) + _, b := makeTestBom() + bm := &BomMeta{} + oc := NewOctopartClient("") + oc.AttachMarketInfoBom(b) + t.Errorf("unimplemented") + DumpBomAsText(bm, b, os.Stdout) } - @@ -1,14 +1,14 @@ package main import ( + "code.google.com/p/gorilla/sessions" "fmt" "html/template" "log" "net/http" + "path/filepath" "regexp" - "path/filepath" - "time" - "code.google.com/p/gorilla/sessions" + "time" ) var ( @@ -57,10 +57,10 @@ func baseHandler(w http.ResponseWriter, r *http.Request) { } func homeController(w http.ResponseWriter, r *http.Request) (err error) { - session, _ := store.Get(r, "bommom") + session, _ := store.Get(r, "bommom") context := make(map[string]interface{}) context["Session"] = session.Values - log.Printf("%s\n", session.Values["UserName"]) + log.Printf("%s\n", session.Values["UserName"]) context["BomList"], err = bomstore.ListBoms("") if err != nil { return @@ -70,49 +70,49 @@ func homeController(w http.ResponseWriter, r *http.Request) (err error) { } func loginController(w http.ResponseWriter, r *http.Request) (err error) { - session, _ := store.Get(r, "bommom") - context := make(map[string]interface{}) - context["ActionLogin"] = true - context["Session"] = session.Values - if r.Method == "POST" { - if isShortName(r.FormValue("UserName")) != true { - context["Problem"] = "Ugh, need to use a SHORTNAME!" - err = tmplAccount.Execute(w, context) - return - } - audience := "http://localhost:7070" - vResponse := VerifyPersonaAssertion(r.FormValue("assertion"), audience) - if vResponse.Okay() { - session.Values["UserName"] = r.FormValue("UserName") - session.Values["Email"] = vResponse.Email - session.Save(r, w) - context["Session"] = session.Values - http.Redirect(w, r, "/", 302) - return - } else { - context["Problem"] = vResponse.Reason - err = tmplAccount.Execute(w, context) - return - } - } + session, _ := store.Get(r, "bommom") + context := make(map[string]interface{}) + context["ActionLogin"] = true + context["Session"] = session.Values + if r.Method == "POST" { + if isShortName(r.FormValue("UserName")) != true { + context["Problem"] = "Ugh, need to use a SHORTNAME!" + err = tmplAccount.Execute(w, context) + return + } + audience := "http://localhost:7070" + vResponse := VerifyPersonaAssertion(r.FormValue("assertion"), audience) + if vResponse.Okay() { + session.Values["UserName"] = r.FormValue("UserName") + session.Values["Email"] = vResponse.Email + session.Save(r, w) + context["Session"] = session.Values + http.Redirect(w, r, "/", 302) + return + } else { + context["Problem"] = vResponse.Reason + err = tmplAccount.Execute(w, context) + return + } + } err = tmplAccount.Execute(w, context) return } func logoutController(w http.ResponseWriter, r *http.Request) (err error) { - session, _ := store.Get(r, "bommom") - context := make(map[string]interface{}) - delete(session.Values, "UserName") - delete(session.Values, "Email") - session.Save(r, w) - context["Session"] = session.Values - context["ActionLogout"] = true + session, _ := store.Get(r, "bommom") + context := make(map[string]interface{}) + delete(session.Values, "UserName") + delete(session.Values, "Email") + session.Save(r, w) + context["Session"] = session.Values + context["ActionLogout"] = true err = tmplAccount.Execute(w, context) return } func userController(w http.ResponseWriter, r *http.Request, user, extra string) (err error) { - session, _ := store.Get(r, "bommom") + session, _ := store.Get(r, "bommom") if !isShortName(user) { http.Error(w, "invalid username: "+user, 400) return @@ -124,9 +124,9 @@ func userController(w http.ResponseWriter, r *http.Request, user, extra string) } context := make(map[string]interface{}) context["BomList"], err = bomstore.ListBoms(ShortName(user)) - if user == "common" { - context["IsCommon"] = true - } + if user == "common" { + context["IsCommon"] = true + } context["UserName"] = user context["Session"] = session.Values if err != nil { @@ -137,7 +137,7 @@ func userController(w http.ResponseWriter, r *http.Request, user, extra string) } func bomController(w http.ResponseWriter, r *http.Request, user, name string) (err error) { - session, _ := store.Get(r, "bommom") + session, _ := store.Get(r, "bommom") if !isShortName(user) { http.Error(w, "invalid username: "+user, 400) return @@ -150,7 +150,7 @@ func bomController(w http.ResponseWriter, r *http.Request, user, name string) (e context["BomMeta"], context["Bom"], err = bomstore.GetHead(ShortName(user), ShortName(name)) context["Session"] = session.Values if err != nil { - http.Error(w, "404 couldn't open bom: " + user + "/" + name, 404) + http.Error(w, "404 couldn't open bom: "+user+"/"+name, 404) return nil } err = tmplBomView.Execute(w, context) @@ -158,7 +158,7 @@ func bomController(w http.ResponseWriter, r *http.Request, user, name string) (e } func bomUploadController(w http.ResponseWriter, r *http.Request, user, name string) (err error) { - session, _ := store.Get(r, "bommom") + session, _ := store.Get(r, "bommom") if !isShortName(user) { http.Error(w, "invalid username: "+user, 400) @@ -170,94 +170,93 @@ func bomUploadController(w http.ResponseWriter, r *http.Request, user, name stri } context := make(map[string]interface{}) context["Session"] = session.Values - context["user"] = ShortName(user) - context["name"] = ShortName(name) + context["user"] = ShortName(user) + context["name"] = ShortName(name) context["BomMeta"], context["Bom"], err = bomstore.GetHead(ShortName(user), ShortName(name)) - switch r.Method { + switch r.Method { case "POST": - err := r.ParseMultipartForm(1024*1024*2) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), 400) - return nil - } - file, fileheader, err := r.FormFile("bomfile") - if err != nil { - log.Println(err) - context["error"] = "bomfile was nil!" - err = tmplBomUpload.Execute(w, context) - return err - } - if file == nil { - log.Println("bomfile was nil") - context["error"] = "bomfile was nil!" - err = tmplBomUpload.Execute(w, context) - return err - } - versionStr := r.FormValue("version") - if len(versionStr) == 0 || isShortName(versionStr) == false { - context["error"] = "Version must be specified and a ShortName!" - context["version"] = versionStr - err = tmplBomUpload.Execute(w, context) - return err - } + err := r.ParseMultipartForm(1024 * 1024 * 2) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), 400) + return nil + } + file, fileheader, err := r.FormFile("bomfile") + if err != nil { + log.Println(err) + context["error"] = "bomfile was nil!" + err = tmplBomUpload.Execute(w, context) + return err + } + if file == nil { + log.Println("bomfile was nil") + context["error"] = "bomfile was nil!" + err = tmplBomUpload.Execute(w, context) + return err + } + versionStr := r.FormValue("version") + if len(versionStr) == 0 || isShortName(versionStr) == false { + context["error"] = "Version must be specified and a ShortName!" + context["version"] = versionStr + err = tmplBomUpload.Execute(w, context) + return err + } - //contentType := fileheader.Header["Content-Type"][0] - var b *Bom - var bm *BomMeta + //contentType := fileheader.Header["Content-Type"][0] + var b *Bom + var bm *BomMeta - switch filepath.Ext(fileheader.Filename) { - case ".json": - bm, b, err = LoadBomFromJSON(file) - if err != nil { - context["error"] = "Problem loading JSON file" - err = tmplBomUpload.Execute(w, context) - return err - } - case ".csv": - b, err = LoadBomFromCSV(file) - bm = &BomMeta{} - if err != nil { - context["error"] = "Problem loading CSV file: " + err.Error() - err = tmplBomUpload.Execute(w, context) - return err - } - case ".xml": - bm, b, err = LoadBomFromXML(file) - if err != nil { - context["error"] = "Problem loading XML file" - err = tmplBomUpload.Execute(w, context) - return err - } - default: - context["error"] = "Unknown file type: " + string(fileheader.Filename) - log.Fatal(context["error"]) - err = tmplBomUpload.Execute(w, context) - return err - } - bm.Owner = user - bm.Name = name - b.Progeny = "File uploaded from " + fileheader.Filename - b.Created = time.Now() - b.Version = string(versionStr) - if err := bomstore.Persist(bm, b, ShortName(versionStr)); err != nil { - context["error"] = "Problem saving to datastore: " + err.Error() - err = tmplBomUpload.Execute(w, context) - } - http.Redirect(w, r, "//" + user + "/" + name + "/", 302) - return err + switch filepath.Ext(fileheader.Filename) { + case ".json": + bm, b, err = LoadBomFromJSON(file) + if err != nil { + context["error"] = "Problem loading JSON file" + err = tmplBomUpload.Execute(w, context) + return err + } + case ".csv": + b, err = LoadBomFromCSV(file) + bm = &BomMeta{} + if err != nil { + context["error"] = "Problem loading CSV file: " + err.Error() + err = tmplBomUpload.Execute(w, context) + return err + } + case ".xml": + bm, b, err = LoadBomFromXML(file) + if err != nil { + context["error"] = "Problem loading XML file" + err = tmplBomUpload.Execute(w, context) + return err + } + default: + context["error"] = "Unknown file type: " + string(fileheader.Filename) + log.Fatal(context["error"]) + err = tmplBomUpload.Execute(w, context) + return err + } + bm.Owner = user + bm.Name = name + b.Progeny = "File uploaded from " + fileheader.Filename + b.Created = time.Now() + b.Version = string(versionStr) + if err := bomstore.Persist(bm, b, ShortName(versionStr)); err != nil { + context["error"] = "Problem saving to datastore: " + err.Error() + err = tmplBomUpload.Execute(w, context) + } + http.Redirect(w, r, "//"+user+"/"+name+"/", 302) + return err case "GET": - err = tmplBomUpload.Execute(w, context) - return err - default: - http.Error(w, "bad method", 405) - return nil - } + err = tmplBomUpload.Execute(w, context) + return err + default: + http.Error(w, "bad method", 405) + return nil + } return } - func serveCmd() { var err error |