package ods import ( "archive/zip" "bytes" "dev.tandem.ws/tandem/camper/pkg/auth" "dev.tandem.ws/tandem/camper/pkg/template" "encoding/xml" "fmt" "net/http" "strings" "time" "dev.tandem.ws/tandem/camper/pkg/database" "dev.tandem.ws/tandem/camper/pkg/locale" ) const ( mimetype = "application/vnd.oasis.opendocument.spreadsheet" metaDashInfManifestXml = ` ` metaXml = ` Camper ` stylesXml = ` ` ) func WriteTable[K interface{}](rows []*K, columns []string, locale *locale.Locale, writeRow func(*strings.Builder, *K) error) ([]byte, error) { var sb strings.Builder sb.WriteString(` / / `) sb.WriteString(fmt.Sprintf(" \n", len(columns))) sb.WriteString(` `) for _, t := range columns { if err := WriteCellString(&sb, locale.GetC(t, "header")); err != nil { return nil, err } } sb.WriteString(" \n") for _, row := range rows { sb.WriteString(" \n") if err := writeRow(&sb, row); err != nil { return nil, err } sb.WriteString(" \n") } sb.WriteString(` `) return writeOds(sb.String()) } func writeOds(content string) ([]byte, error) { buf := new(bytes.Buffer) ods := zip.NewWriter(buf) if err := writeOdsFile(ods, "mimetype", mimetype, zip.Store); err != nil { return nil, err } if err := writeOdsFile(ods, "META-INF/manifest.xml", metaDashInfManifestXml, zip.Deflate); err != nil { return nil, err } if err := writeOdsFile(ods, "meta.xml", metaXml, zip.Deflate); err != nil { return nil, err } if err := writeOdsFile(ods, "styles.xml", stylesXml, zip.Deflate); err != nil { return nil, err } if err := writeOdsFile(ods, "content.xml", content, zip.Deflate); err != nil { return nil, err } if err := ods.Close(); err != nil { return nil, err } return buf.Bytes(), nil } func writeOdsFile(ods *zip.Writer, name string, content string, method uint16) error { f, err := ods.CreateHeader(&zip.FileHeader{ Name: name, Method: method, Modified: time.Now(), }) if err != nil { return err } _, err = f.Write([]byte(content)) return err } func WriteCellString(sb *strings.Builder, s string) error { sb.WriteString(` `) if err := xml.EscapeText(sb, []byte(s)); err != nil { return err } sb.WriteString("\n") return nil } func WriteCellDate(sb *strings.Builder, t time.Time) { sb.WriteString(fmt.Sprintf(" %s\n", t.Format(database.ISODateFormat), t.Format("02/01/06"))) } func WriteCellFloat(sb *strings.Builder, s string, company *auth.Company, locale *locale.Locale) { sb.WriteString(fmt.Sprintf(" %s\n", s, template.FormatPrice(s, locale.Language, locale.CurrencyPattern, company.DecimalDigits, company.CurrencySymbol))) } func MustWriteResponse(w http.ResponseWriter, ods []byte, filename string) { w.Header().Set("Content-Type", "application/vnd.oasis.opendocument.spreadsheet") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) w.WriteHeader(http.StatusOK) if _, err := w.Write(ods); err != nil { panic(err) } }