diff --git a/migrate.go b/migrate.go index c4f314e..b91f355 100755 --- a/migrate.go +++ b/migrate.go @@ -1,33 +1,33 @@ -package main - -import ( - "fmt" - "io/ioutil" - "path" -) - -func migrate(pathToOldData, pathToData string) error { - files, err := ioutil.ReadDir(pathToOldData) - if len(files) == 0 { - return err - } - for _, f := range files { - if f.Mode().IsDir() { - continue - } - fmt.Printf("Migrating %s", f.Name()) - p := Open(f.Name()) - bData, err := ioutil.ReadFile(path.Join(pathToOldData, f.Name())) - if err != nil { - return err - } - err = p.Update(string(bData)) - if err != nil { - return err - } - if err = p.Save(); err != nil { - return err - } - } - return nil -} +package main + +import ( + "fmt" + "io/ioutil" + "path" +) + +func migrate(pathToOldData, pathToData string) error { + files, err := ioutil.ReadDir(pathToOldData) + if len(files) == 0 { + return err + } + for _, f := range files { + if f.Mode().IsDir() { + continue + } + fmt.Printf("Migrating %s", f.Name()) + p := Open(f.Name()) + bData, err := ioutil.ReadFile(path.Join(pathToOldData, f.Name())) + if err != nil { + return err + } + err = p.Update(string(bData)) + if err != nil { + return err + } + if err = p.Save(); err != nil { + return err + } + } + return nil +} diff --git a/page.go b/page.go index 3d6b877..a766124 100755 --- a/page.go +++ b/page.go @@ -1,163 +1,163 @@ -package main - -import ( - "encoding/json" - "io/ioutil" - "os" - "path" - "path/filepath" - "regexp" - "sort" - "strings" - "sync" - "time" - - "github.com/schollz/versionedtext" -) - -// Page is the basic struct -type Page struct { - Name string - Text versionedtext.VersionedText - Meta string - RenderedPage string - IsLocked bool - PassphraseToUnlock string - IsEncrypted bool - IsPrimedForSelfDestruct bool - IsPublished bool -} - -func (p Page) LastEditTime() time.Time { - return time.Unix(p.LastEditUnixTime(), 0) -} - -func (p Page) LastEditUnixTime() int64 { - return p.Text.LastEditTime() / 1000000000 -} - -func Open(name string) (p *Page) { - p = new(Page) - p.Name = name - p.Text = versionedtext.NewVersionedText("") - p.Render() - bJSON, err := ioutil.ReadFile(path.Join(pathToData, encodeToBase32(strings.ToLower(name))+".json")) - if err != nil { - return - } - err = json.Unmarshal(bJSON, &p) - if err != nil { - p = new(Page) - } - return p -} - -type DirectoryEntry struct { - Name string - Length int - Numchanges int - LastEdited time.Time -} - -func (d DirectoryEntry) LastEditTime() string { - return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006") -} - -func DirectoryList() []DirectoryEntry { - files, _ := ioutil.ReadDir(pathToData) - entries := make([]DirectoryEntry, len(files)) - for i, f := range files { - name := DecodeFileName(f.Name()) - p := Open(name) - entries[i] = DirectoryEntry{ - Name: name, - Length: len(p.Text.GetCurrent()), - Numchanges: p.Text.NumEdits(), - LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0), - } - } - sort.Slice(entries, func(i, j int) bool { return entries[i].LastEdited.After(entries[j].LastEdited) }) - return entries -} - -func DecodeFileName(s string) string { - s2, _ := decodeFromBase32(strings.Split(s, ".")[0]) - return s2 -} - -// Update cleans the text and updates the versioned text -// and generates a new render -func (p *Page) Update(newText string) error { - // Trim space from end - newText = strings.TrimRight(newText, "\n\t ") - - // Update the versioned text - p.Text.Update(newText) - - // Render the new page - p.Render() - - return p.Save() -} - -var rBracketPage = regexp.MustCompile(`\[\[(.*?)\]\]`) - -func (p *Page) Render() { - if p.IsEncrypted { - p.RenderedPage = "" + p.Text.GetCurrent() + "" - return - } - - // Convert [[page]] to [page](/page/view) - currentText := p.Text.GetCurrent() - for _, s := range rBracketPage.FindAllString(currentText, -1) { - currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1) - } - p.Text.Update(currentText) - p.RenderedPage = MarkdownToHtml(p.Text.GetCurrent()) -} - -var saveMut = sync.Mutex{} - -func (p *Page) Save() error { - saveMut.Lock() - defer saveMut.Unlock() - bJSON, err := json.MarshalIndent(p, "", " ") - if err != nil { - return err - } - return ioutil.WriteFile(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"), bJSON, 0644) -} - -func (p *Page) ChildPageNames() []string { - prefix := strings.ToLower(p.Name + ": ") - files, err := filepath.Glob(path.Join(pathToData, "*")) - if err != nil { - panic("Filepath pattern cannot be malformed") - } - - result := []string{} - for i := range files { - basename := filepath.Base(files[i]) - if strings.HasSuffix(basename, ".json") { - cname, err := decodeFromBase32(basename[:len(basename)-len(".json")]) - if err == nil && strings.HasPrefix(strings.ToLower(cname), prefix) { - result = append(result, cname) - } - } - } - return result -} - -func (p *Page) IsNew() bool { - return !exists(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json")) -} - -func (p *Page) Erase() error { - log.Trace("Erasing " + p.Name) - return os.Remove(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json")) -} - -func (p *Page) Published() bool { - return p.IsPublished -} +package main + +import ( + "encoding/json" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + "sort" + "strings" + "sync" + "time" + + "github.com/schollz/versionedtext" +) + +// Page is the basic struct +type Page struct { + Name string + Text versionedtext.VersionedText + Meta string + RenderedPage string + IsLocked bool + PassphraseToUnlock string + IsEncrypted bool + IsPrimedForSelfDestruct bool + IsPublished bool +} + +func (p Page) LastEditTime() time.Time { + return time.Unix(p.LastEditUnixTime(), 0) +} + +func (p Page) LastEditUnixTime() int64 { + return p.Text.LastEditTime() / 1000000000 +} + +func Open(name string) (p *Page) { + p = new(Page) + p.Name = name + p.Text = versionedtext.NewVersionedText("") + p.Render() + bJSON, err := ioutil.ReadFile(path.Join(pathToData, encodeToBase32(strings.ToLower(name))+".json")) + if err != nil { + return + } + err = json.Unmarshal(bJSON, &p) + if err != nil { + p = new(Page) + } + return p +} + +type DirectoryEntry struct { + Name string + Length int + Numchanges int + LastEdited time.Time +} + +func (d DirectoryEntry) LastEditTime() string { + return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006") +} + +func DirectoryList() []DirectoryEntry { + files, _ := ioutil.ReadDir(pathToData) + entries := make([]DirectoryEntry, len(files)) + for i, f := range files { + name := DecodeFileName(f.Name()) + p := Open(name) + entries[i] = DirectoryEntry{ + Name: name, + Length: len(p.Text.GetCurrent()), + Numchanges: p.Text.NumEdits(), + LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0), + } + } + sort.Slice(entries, func(i, j int) bool { return entries[i].LastEdited.After(entries[j].LastEdited) }) + return entries +} + +func DecodeFileName(s string) string { + s2, _ := decodeFromBase32(strings.Split(s, ".")[0]) + return s2 +} + +// Update cleans the text and updates the versioned text +// and generates a new render +func (p *Page) Update(newText string) error { + // Trim space from end + newText = strings.TrimRight(newText, "\n\t ") + + // Update the versioned text + p.Text.Update(newText) + + // Render the new page + p.Render() + + return p.Save() +} + +var rBracketPage = regexp.MustCompile(`\[\[(.*?)\]\]`) + +func (p *Page) Render() { + if p.IsEncrypted { + p.RenderedPage = "" + p.Text.GetCurrent() + "" + return + } + + // Convert [[page]] to [page](/page/view) + currentText := p.Text.GetCurrent() + for _, s := range rBracketPage.FindAllString(currentText, -1) { + currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1) + } + p.Text.Update(currentText) + p.RenderedPage = MarkdownToHtml(p.Text.GetCurrent()) +} + +var saveMut = sync.Mutex{} + +func (p *Page) Save() error { + saveMut.Lock() + defer saveMut.Unlock() + bJSON, err := json.MarshalIndent(p, "", " ") + if err != nil { + return err + } + return ioutil.WriteFile(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"), bJSON, 0644) +} + +func (p *Page) ChildPageNames() []string { + prefix := strings.ToLower(p.Name + ": ") + files, err := filepath.Glob(path.Join(pathToData, "*")) + if err != nil { + panic("Filepath pattern cannot be malformed") + } + + result := []string{} + for i := range files { + basename := filepath.Base(files[i]) + if strings.HasSuffix(basename, ".json") { + cname, err := decodeFromBase32(basename[:len(basename)-len(".json")]) + if err == nil && strings.HasPrefix(strings.ToLower(cname), prefix) { + result = append(result, cname) + } + } + } + return result +} + +func (p *Page) IsNew() bool { + return !exists(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json")) +} + +func (p *Page) Erase() error { + log.Trace("Erasing " + p.Name) + return os.Remove(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json")) +} + +func (p *Page) Published() bool { + return p.IsPublished +} diff --git a/page_test.go b/page_test.go index 378269e..1816e55 100755 --- a/page_test.go +++ b/page_test.go @@ -1,72 +1,72 @@ -package main - -import ( - "os" - "strings" - "testing" -) - -func TestListFiles(t *testing.T) { - pathToData = "testdata" - os.MkdirAll(pathToData, 0755) - defer os.RemoveAll(pathToData) - p := Open("testpage") - p.Update("Some data") - p = Open("testpage2") - p.Update("A different bunch of data") - p = Open("testpage3") - p.Update("Not much else") - n := DirectoryList() - if len(n) != 3 { - t.Error("Expected three directory entries") - t.FailNow() - } - if n[0].Name != "testpage" { - t.Error("Expected testpage to be first") - } - if n[1].Name != "testpage2" { - t.Error("Expected testpage2 to be second") - } - if n[2].Name != "testpage3" { - t.Error("Expected testpage3 to be last") - } -} - -func TestGeneral(t *testing.T) { - pathToData = "testdata" - os.MkdirAll(pathToData, 0755) - defer os.RemoveAll(pathToData) - p := Open("testpage") - err := p.Update("**bold**") - if err != nil { - t.Error(err) - } - if strings.TrimSpace(p.RenderedPage) != "

bold

" { - t.Errorf("Did not render: '%s'", p.RenderedPage) - } - err = p.Update("**bold** and *italic*") - if err != nil { - t.Error(err) - } - p.Save() - - p2 := Open("testpage") - if strings.TrimSpace(p2.RenderedPage) != "

bold and italic

" { - t.Errorf("Did not render: '%s'", p2.RenderedPage) - } - - p3 := Open("testpage: childpage") - err = p3.Update("**child content**") - if err != nil { - t.Error(err) - } - - children := p.ChildPageNames() - if len(children) != 1 { - t.Errorf("Expected 1 child page to be found, got %d", len(children)) - return - } - if children[0] != "testpage: childpage" { - t.Errorf("Expected child page %s to be found (got %s)", "testpage: childpage", children[0]) - } -} +package main + +import ( + "os" + "strings" + "testing" +) + +func TestListFiles(t *testing.T) { + pathToData = "testdata" + os.MkdirAll(pathToData, 0755) + defer os.RemoveAll(pathToData) + p := Open("testpage") + p.Update("Some data") + p = Open("testpage2") + p.Update("A different bunch of data") + p = Open("testpage3") + p.Update("Not much else") + n := DirectoryList() + if len(n) != 3 { + t.Error("Expected three directory entries") + t.FailNow() + } + if n[0].Name != "testpage" { + t.Error("Expected testpage to be first") + } + if n[1].Name != "testpage2" { + t.Error("Expected testpage2 to be second") + } + if n[2].Name != "testpage3" { + t.Error("Expected testpage3 to be last") + } +} + +func TestGeneral(t *testing.T) { + pathToData = "testdata" + os.MkdirAll(pathToData, 0755) + defer os.RemoveAll(pathToData) + p := Open("testpage") + err := p.Update("**bold**") + if err != nil { + t.Error(err) + } + if strings.TrimSpace(p.RenderedPage) != "

bold

" { + t.Errorf("Did not render: '%s'", p.RenderedPage) + } + err = p.Update("**bold** and *italic*") + if err != nil { + t.Error(err) + } + p.Save() + + p2 := Open("testpage") + if strings.TrimSpace(p2.RenderedPage) != "

bold and italic

" { + t.Errorf("Did not render: '%s'", p2.RenderedPage) + } + + p3 := Open("testpage: childpage") + err = p3.Update("**child content**") + if err != nil { + t.Error(err) + } + + children := p.ChildPageNames() + if len(children) != 1 { + t.Errorf("Expected 1 child page to be found, got %d", len(children)) + return + } + if children[0] != "testpage: childpage" { + t.Errorf("Expected child page %s to be found (got %s)", "testpage: childpage", children[0]) + } +} diff --git a/utils_test.go b/utils_test.go index 6f363df..81d79c2 100755 --- a/utils_test.go +++ b/utils_test.go @@ -1,35 +1,35 @@ -package main - -import ( - "testing" -) - -func BenchmarkAlliterativeAnimal(b *testing.B) { - for i := 0; i < b.N; i++ { - randomAlliterateCombo() - } -} - -func TestReverseList(t *testing.T) { - s := []int64{1, 10, 2, 20} - if reverseSliceInt64(s)[0] != 20 { - t.Errorf("Could not reverse: %v", s) - } - s2 := []string{"a", "b", "d", "c"} - if reverseSliceString(s2)[0] != "c" { - t.Errorf("Could not reverse: %v", s2) - } -} - -func TestHashing(t *testing.T) { - p := HashPassword("1234") - log.Debug(p) - err := CheckPasswordHash("1234", p) - if err != nil { - t.Errorf("Should be correct password") - } - err = CheckPasswordHash("1234lkjklj", p) - if err == nil { - t.Errorf("Should NOT be correct password") - } -} +package main + +import ( + "testing" +) + +func BenchmarkAlliterativeAnimal(b *testing.B) { + for i := 0; i < b.N; i++ { + randomAlliterateCombo() + } +} + +func TestReverseList(t *testing.T) { + s := []int64{1, 10, 2, 20} + if reverseSliceInt64(s)[0] != 20 { + t.Errorf("Could not reverse: %v", s) + } + s2 := []string{"a", "b", "d", "c"} + if reverseSliceString(s2)[0] != "c" { + t.Errorf("Could not reverse: %v", s2) + } +} + +func TestHashing(t *testing.T) { + p := HashPassword("1234") + log.Debug(p) + err := CheckPasswordHash("1234", p) + if err != nil { + t.Errorf("Should be correct password") + } + err = CheckPasswordHash("1234lkjklj", p) + if err == nil { + t.Errorf("Should NOT be correct password") + } +}