Skip to content

Commit 712e031

Browse files
author
Anand
committed
Export actions
1 parent 10f8feb commit 712e031

File tree

1 file changed

+350
-0
lines changed

1 file changed

+350
-0
lines changed

actions.go

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package main
33

44
import (
55
"bufio"
6+
"encoding/csv"
67
"errors"
78
"fmt"
89
"os"
10+
"os/exec"
911
"path/filepath"
1012
"strconv"
1113
"strings"
@@ -627,3 +629,351 @@ func decryptDatabase(dbPath string) (error, string) {
627629

628630
return err, passwd
629631
}
632+
633+
// Export data to a varity of file types
634+
func exportToFile(fileName string) error {
635+
636+
var err error
637+
ext := filepath.Ext(fileName)
638+
639+
switch strings.ToLower(ext) {
640+
case ".csv":
641+
err = exportToCsv(fileName)
642+
case ".md":
643+
err = exportToMarkdown(fileName)
644+
case ".html":
645+
err = exportToHTML(fileName)
646+
case ".pdf":
647+
err = exportToPDF(fileName)
648+
default:
649+
return fmt.Errorf("format %s not supported", ext)
650+
}
651+
652+
if err != nil {
653+
fmt.Printf("Error exporting to \"%s\" - \"%s\"\n", fileName, err.Error())
654+
return err
655+
} else {
656+
if _, err = os.Stat(fileName); err == nil {
657+
fmt.Printf("Exported to %s.\n", fileName)
658+
// Chmod 600
659+
os.Chmod(fileName, 0600)
660+
return nil
661+
}
662+
}
663+
664+
return err
665+
}
666+
667+
// Export current database to markdown
668+
func exportToMarkdown(fileName string) error {
669+
670+
var err error
671+
var dataArray [][]string
672+
var fh *os.File
673+
var maxLengths [7]int
674+
var headers []string = []string{" ID ", " Title ", " User ", " URL ", " Password ", " Notes ", " Modified "}
675+
676+
err, dataArray = entriesToStringArray(false)
677+
678+
if err != nil {
679+
fmt.Printf("Error exporting entries to string array - \"%s\"\n", err.Error())
680+
return err
681+
}
682+
683+
for _, record := range dataArray {
684+
for idx, field := range record {
685+
686+
if len(field) > maxLengths[idx] {
687+
maxLengths[idx] = len(field)
688+
}
689+
}
690+
}
691+
692+
// fmt.Printf("%+v\n", maxLengths)
693+
fh, err = os.Create(fileName)
694+
if err != nil {
695+
fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error())
696+
return err
697+
}
698+
699+
defer fh.Close()
700+
701+
writer := bufio.NewWriter(fh)
702+
703+
// Write markdown header
704+
for idx, length := range maxLengths {
705+
delta := length - len(headers[idx])
706+
// fmt.Printf("%d\n", delta)
707+
if delta > 0 {
708+
for i := 0; i < delta+2; i++ {
709+
headers[idx] += " "
710+
}
711+
}
712+
}
713+
714+
writer.WriteString(" |" + strings.Join(headers, "|") + "|\n")
715+
716+
// Write line separator
717+
writer.WriteString(" | ")
718+
for _, length := range maxLengths {
719+
720+
for i := 0; i < length; i++ {
721+
writer.WriteString("-")
722+
}
723+
writer.WriteString(" | ")
724+
}
725+
writer.WriteString("\n")
726+
727+
// Write records
728+
for _, record := range dataArray {
729+
writer.WriteString(" | ")
730+
for _, field := range record {
731+
writer.WriteString(field + " | ")
732+
}
733+
writer.WriteString("\n")
734+
}
735+
736+
writer.Flush()
737+
738+
return nil
739+
740+
}
741+
742+
// This needs pandoc and pdflatex support
743+
func exportToPDF(fileName string) error {
744+
745+
var err error
746+
var tmpFile string
747+
var passwd string
748+
var pdfTkFound bool
749+
750+
cmd := exec.Command("which", "pandoc")
751+
if _, err = cmd.Output(); err != nil {
752+
return errors.New("pandoc not found")
753+
}
754+
755+
cmd = exec.Command("which", "pdftk")
756+
if _, err = cmd.Output(); err != nil {
757+
fmt.Printf("pdftk not found, PDF won't be secure!\n")
758+
} else {
759+
pdfTkFound = true
760+
}
761+
762+
if pdfTkFound {
763+
fmt.Printf("Password: ")
764+
err, passwd = readPassword()
765+
}
766+
767+
tmpFile = randomFileName(os.TempDir(), ".tmp")
768+
// fmt.Printf("Temp file => %s\n", tmpFile)
769+
err = exportToMarkdownLimited(tmpFile)
770+
771+
if err == nil {
772+
var args []string = []string{"-o", fileName, "-f", "markdown", "-V", "geometry:landscape", "--columns=600", "--pdf-engine", "xelatex", "--dpi=150", tmpFile}
773+
774+
cmd = exec.Command("pandoc", args...)
775+
_, err = cmd.Output()
776+
// Remove tmpfile
777+
os.Remove(tmpFile)
778+
779+
// If the file is generated, encrypt it if pdfTkFound
780+
if _, err = os.Stat(fileName); err == nil {
781+
fmt.Printf("\nFile %s created without password.\n", fileName)
782+
783+
if pdfTkFound {
784+
tmpFile = randomFileName(".", ".pdf")
785+
// fmt.Printf("pdf file => %s\n", tmpFile)
786+
args = []string{fileName, "output", tmpFile, "user_pw", passwd}
787+
cmd = exec.Command("pdftk", args...)
788+
_, err = cmd.Output()
789+
790+
if err == nil {
791+
// Copy over
792+
fmt.Printf("Added password to %s.\n", fileName)
793+
os.Remove(fileName)
794+
err = os.Rename(tmpFile, fileName)
795+
} else {
796+
fmt.Printf("Error adding password to pdf - \"%s\"\n", err.Error())
797+
}
798+
}
799+
}
800+
}
801+
802+
return err
803+
804+
}
805+
806+
// Export current database to markdown minus the long fields
807+
func exportToMarkdownLimited(fileName string) error {
808+
809+
var err error
810+
var dataArray [][]string
811+
var fh *os.File
812+
var maxLengths [6]int
813+
var headers []string = []string{" ID ", " Title ", " User ", " URL ", " Password ", " Modified "}
814+
815+
err, dataArray = entriesToStringArray(true)
816+
817+
if err != nil {
818+
fmt.Printf("Error exporting entries to string array - \"%s\"\n", err.Error())
819+
return err
820+
}
821+
822+
for _, record := range dataArray {
823+
for idx, field := range record {
824+
825+
if len(field) > maxLengths[idx] {
826+
maxLengths[idx] = len(field)
827+
}
828+
}
829+
}
830+
831+
// fmt.Printf("%+v\n", maxLengths)
832+
fh, err = os.Create(fileName)
833+
if err != nil {
834+
fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error())
835+
return err
836+
}
837+
838+
defer fh.Close()
839+
840+
writer := bufio.NewWriter(fh)
841+
842+
// Write markdown header
843+
for idx, length := range maxLengths {
844+
delta := length - len(headers[idx])
845+
// fmt.Printf("%d\n", delta)
846+
if delta > 0 {
847+
for i := 0; i < delta+2; i++ {
848+
headers[idx] += " "
849+
}
850+
}
851+
}
852+
853+
writer.WriteString(" |" + strings.Join(headers, "|") + "|\n")
854+
855+
// Write line separator
856+
writer.WriteString(" | ")
857+
for _, length := range maxLengths {
858+
859+
for i := 0; i < length; i++ {
860+
writer.WriteString("-")
861+
}
862+
writer.WriteString(" | ")
863+
}
864+
writer.WriteString("\n")
865+
866+
// Write records
867+
for _, record := range dataArray {
868+
writer.WriteString(" | ")
869+
for _, field := range record {
870+
writer.WriteString(field + " | ")
871+
}
872+
writer.WriteString("\n")
873+
}
874+
875+
writer.Flush()
876+
877+
return nil
878+
879+
}
880+
881+
// Export current database to html
882+
func exportToHTML(fileName string) error {
883+
884+
var err error
885+
var dataArray [][]string
886+
var fh *os.File
887+
var headers []string = []string{" ID ", " Title ", " User ", " URL ", " Password ", " Notes ", " Modified "}
888+
889+
err, dataArray = entriesToStringArray(false)
890+
891+
if err != nil {
892+
fmt.Printf("Error exporting entries to string array - \"%s\"\n", err.Error())
893+
return err
894+
}
895+
896+
// fmt.Printf("%+v\n", maxLengths)
897+
fh, err = os.Create(fileName)
898+
if err != nil {
899+
fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error())
900+
return err
901+
}
902+
903+
defer fh.Close()
904+
905+
writer := bufio.NewWriter(fh)
906+
907+
writer.WriteString("<html><body>\n")
908+
writer.WriteString("<table cellPadding=\"2\" cellSpacing=\"2\" border=\"1\">\n")
909+
writer.WriteString("<theader>\n")
910+
911+
for _, h := range headers {
912+
writer.WriteString(fmt.Sprintf("<th>%s</th>", h))
913+
}
914+
writer.WriteString("</theader>\n")
915+
writer.WriteString("<tbody>\n")
916+
917+
// Write records
918+
for _, record := range dataArray {
919+
writer.WriteString("<tr>")
920+
for _, field := range record {
921+
writer.WriteString(fmt.Sprintf("<td>%s</td>", field))
922+
}
923+
writer.WriteString("</tr>\n")
924+
}
925+
writer.WriteString("</tbody>\n")
926+
writer.WriteString("</table>\n")
927+
928+
writer.WriteString("</body></html>\n")
929+
930+
writer.Flush()
931+
932+
return nil
933+
934+
}
935+
936+
// Export current database to CSV
937+
func exportToCsv(fileName string) error {
938+
939+
var err error
940+
var dataArray [][]string
941+
var fh *os.File
942+
943+
err, dataArray = entriesToStringArray(false)
944+
945+
if err != nil {
946+
fmt.Printf("Error exporting entries to string array - \"%s\"\n", err.Error())
947+
return err
948+
}
949+
950+
fh, err = os.Create(fileName)
951+
if err != nil {
952+
fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error())
953+
return err
954+
}
955+
956+
writer := csv.NewWriter(fh)
957+
958+
// Write header
959+
writer.Write([]string{"ID", "Title", "User", "URL", "Password", "Notes", "Modified"})
960+
961+
for idx, record := range dataArray {
962+
if err = writer.Write(record); err != nil {
963+
fmt.Printf("Error writing record #%d to %s - \"%s\"\n", idx+1, fileName, err.Error())
964+
break
965+
}
966+
}
967+
968+
writer.Flush()
969+
970+
if err != nil {
971+
return err
972+
}
973+
974+
os.Chmod(fileName, 0600)
975+
fmt.Printf("!WARNING: Passwords are stored in plain-text!\n")
976+
fmt.Printf("Exported %d records to %s .\n", len(dataArray), fileName)
977+
978+
return nil
979+
}

0 commit comments

Comments
 (0)