From 965989530cf7ef882818db9c9ed40c64aeae2111 Mon Sep 17 00:00:00 2001 From: Zack Scholl Date: Sun, 7 Feb 2016 18:31:47 -0500 Subject: [PATCH] Storing DIffs now...might not be compatible? --- db.go | 25 ++++++++++++++++++++----- main.go | 8 ++++++-- routes.go | 26 +++++++++++++------------- static/img/gomascot.png | Bin 0 -> 10498 bytes static/img/raspberrypi.png | Bin 0 -> 8856 bytes utils.go | 30 +++++++++++++++++++++++++++++- websockets.go | 22 ++++++++++++---------- 7 files changed, 80 insertions(+), 31 deletions(-) create mode 100755 static/img/gomascot.png create mode 100755 static/img/raspberrypi.png diff --git a/db.go b/db.go index 47c9878..1b1c176 100644 --- a/db.go +++ b/db.go @@ -7,6 +7,7 @@ import ( "time" "github.com/boltdb/bolt" + "github.com/sergi/go-diff/diffmatchpatch" ) var db *bolt.DB @@ -33,11 +34,13 @@ func Close() { // Data for storing in DB type CowyoData struct { - Title string - Text string + Title string + CurrentText string + Diffs []string + Timestamps []string } -func (p *CowyoData) load() error { +func (p *CowyoData) load(title string) error { if !open { return fmt.Errorf("db must be opened before saving!") } @@ -47,9 +50,14 @@ func (p *CowyoData) load() error { if b == nil { return nil } - k := []byte(p.Title) + k := []byte(title) val := b.Get(k) if val == nil { + // make new one + p.Title = title + p.CurrentText = "" + p.Diffs = []string{} + p.Timestamps = []string{} return nil } err = p.decode(val) @@ -65,7 +73,7 @@ func (p *CowyoData) load() error { return nil } -func (p *CowyoData) save() error { +func (p *CowyoData) save(newText string) error { if !open { return fmt.Errorf("db must be opened before saving") } @@ -74,6 +82,13 @@ func (p *CowyoData) save() error { if err != nil { return fmt.Errorf("create bucket: %s", err) } + // find diffs + dmp := diffmatchpatch.New() + diffs := dmp.DiffMain(p.CurrentText, newText, true) + delta := dmp.DiffToDelta(diffs) + p.CurrentText = newText + p.Timestamps = append(p.Timestamps, time.Now().String()) + p.Diffs = append(p.Diffs, delta) enc, err := p.encode() if err != nil { return fmt.Errorf("could not encode CowyoData: %s", err) diff --git a/main.go b/main.go index 2d37ebe..601a256 100644 --- a/main.go +++ b/main.go @@ -55,10 +55,14 @@ Options:`) defer Close() // Default page - p := CowyoData{"about", about_page} - p.save() + p := CowyoData{"about", about_page, []string{}, []string{}} + p.save(about_page) fmt.Println(about_page) + var q CowyoData + q.load("SpikySeaSlug") + rebuildTexts(q) + r := gin.Default() r.LoadHTMLGlob("templates/*") r.GET("/", newNote) diff --git a/routes.go b/routes.go index 51f682d..6b22abf 100644 --- a/routes.go +++ b/routes.go @@ -56,12 +56,12 @@ func serveStaticFile(c *gin.Context, option string) { } func renderMarkdown(c *gin.Context, title string) { - p := CowyoData{strings.ToLower(title), ""} - err := p.load() + var p CowyoData + err := p.load(strings.ToLower(title)) if err != nil { panic(err) } - unsafe := blackfriday.MarkdownCommon([]byte(p.Text)) + unsafe := blackfriday.MarkdownCommon([]byte(p.CurrentText)) html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) html2 := string(html) @@ -126,13 +126,13 @@ func renderList(c *gin.Context, title string) { if strings.ToLower(title) == "about" { //}&& strings.Contains(AllowedIPs, c.ClientIP()) != true { c.Redirect(302, "/about/view") } - p := CowyoData{strings.ToLower(title), ""} - err := p.load() + var p CowyoData + err := p.load(strings.ToLower(title)) if err != nil { panic(err) } - listItems, _ := reorderList(p.Text) + listItems, _ := reorderList(p.CurrentText) c.HTML(http.StatusOK, "list.tmpl", gin.H{ "Title": title, @@ -144,25 +144,25 @@ func deleteListItem(c *gin.Context) { lineNum, err := strconv.Atoi(c.DefaultQuery("lineNum", "None")) title := c.Query("title") // shortcut for c.Request.URL.Query().Get("lastname") if err == nil { - p := CowyoData{strings.ToLower(title), ""} - err := p.load() + var p CowyoData + err := p.load(strings.ToLower(title)) if err != nil { panic(err) } - _, listItems := reorderList(p.Text) - + _, listItems := reorderList(p.CurrentText) + newText := p.CurrentText for i, lineString := range listItems { // fmt.Println(i, lineString, lineNum) if i+1 == lineNum { // fmt.Println("MATCHED") if strings.Contains(lineString, "~~") == false { // fmt.Println(p.Text, "("+lineString[2:]+"\n"+")", "~~"+lineString[2:]+"~~"+"\n") - p.Text = strings.Replace(p.Text+"\n", lineString[2:]+"\n", "~~"+lineString[2:]+"~~"+"\n", 1) + newText = strings.Replace(newText+"\n", lineString[2:]+"\n", "~~"+lineString[2:]+"~~"+"\n", 1) } else { - p.Text = strings.Replace(p.Text+"\n", lineString[2:]+"\n", lineString[4:len(lineString)-2]+"\n", 1) + newText = strings.Replace(newText+"\n", lineString[2:]+"\n", lineString[4:len(lineString)-2]+"\n", 1) } - p.save() + p.save(newText) break } } diff --git a/static/img/gomascot.png b/static/img/gomascot.png new file mode 100755 index 0000000000000000000000000000000000000000..c5596caae2e482ee9459c78d255a8a2b1a04e758 GIT binary patch literal 10498 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 literal 0 HcmV?d00001 diff --git a/static/img/raspberrypi.png b/static/img/raspberrypi.png new file mode 100755 index 0000000000000000000000000000000000000000..12c42b773866b5ec6f2f9ac934b0fb647089d2ff GIT binary patch literal 8856 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 aivI(BmkvSb8e+@<0000