func reportWriter(c appengine.Context, w http.ResponseWriter, r *http.Request, s, e time.Time, opt ReportOptions, rep string, format string) { var rows []ReportRow var meta ReportMetadata var err error switch rep { case "classb": rows, meta, err = classbReport(c, s, e, opt) case "adsbclassb": rows, meta, err = adsbClassbReport(c, s, e, opt) case "discrep": rows, meta, err = discrepReport(c, s, e, opt) case "serfr1": rows, meta, err = serfr1Report(c, s, e, opt) case "brixx1": rows, meta, err = brixx1Report(c, s, e, opt) case "serfr1complaints": rows, meta, err = serfr1ComplaintsReport(c, s, e, opt) case "skimmer": rows, meta, err = skimmerReport(c, s, e, opt) case "brixxviolations": rows, meta, err = brixxViolationReport(c, s, e, opt) case "serfr1at": rows, meta, err = serfr1AtReport(c, s, e, opt) } if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Should do something better for this filename := date.NowInPdt().AddDate(0, 0, -1).Format(rep + "-20060102.csv") outFunc := func(csvWriter *csv.Writer) error { csvWriter.Write(rows[0].ToCSVHeaders()) for _, r := range rows { if err := csvWriter.Write(r.ToCSV()); err != nil { return err } } csvWriter.Flush() return nil } if format == "csv" { w.Header().Set("Content-Type", "application/csv") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) csvWriter := csv.NewWriter(w) if err := outFunc(csvWriter); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else if format == "gcs" { newCtx := newappengine.NewContext(r) handle, err := gcs.OpenRW(newCtx, "serfr0-reports", filename, "text/plain") //?"application/csv") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } csvWriter := csv.NewWriter(handle.IOWriter()) if err := outFunc(csvWriter); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if err := handle.Close(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(fmt.Sprintf("OK!\nGCS file '%s' written to bucket", filename))) } else { var params = map[string]interface{}{ "Start": s, "End": e, "Metadata": meta, "Options": opt, } // Is there not a more elegant way to do this kind of thing ? switch rep { case "classb": out := []CBRow{} for _, r := range rows { out = append(out, r.(CBRow)) } params["Rows"] = out case "adsbclassb": out := []ACBRow{} for _, r := range rows { out = append(out, r.(ACBRow)) } params["Rows"] = out case "serfr1", "brixx1", "discrep": out := []SERFR1Row{} for _, r := range rows { out = append(out, r.(SERFR1Row)) } params["Rows"] = out rep = "serfr1" case "serfr1complaints": out := []SCRow{} for _, r := range rows { out = append(out, r.(SCRow)) } params["Rows"] = out case "skimmer": out := []SkimRow{} for _, r := range rows { out = append(out, r.(SkimRow)) } params["Rows"] = out case "brixxviolations": out := []BrixxRow{} for _, r := range rows { out = append(out, r.(BrixxRow)) } params["Rows"] = out case "serfr1at": out := []SERFR1AtRow{} for _, r := range rows { out = append(out, r.(SERFR1AtRow)) } params["Rows"] = out } if err := templates.ExecuteTemplate(w, "report-"+rep, params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } }