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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 US61y{U|?YIboFyt=akR{0B9Gd&;S4c 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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