mirror of
https://github.com/documize/community.git
synced 2025-08-02 20:15:26 +02:00
improve level code
This commit is contained in:
parent
049b83e0b9
commit
5f59e95495
25 changed files with 1104 additions and 461 deletions
|
@ -72,3 +72,71 @@ func Numberize(pages []Page) {
|
|||
prevPageLevel = p.Level
|
||||
}
|
||||
}
|
||||
|
||||
// Levelize ensure page level increments are consistent
|
||||
// after a page is inserted or removed.
|
||||
//
|
||||
// Valid: 1, 2, 3, 4, 4, 4, 2, 1
|
||||
// Invalid: 1, 2, 4, 4, 2, 1 (note the jump from 2 --> 4)
|
||||
//
|
||||
// Rules:
|
||||
// 1. levels can increase by 1 only (e.g. from 1 to 2 to 3 to 4)
|
||||
// 2. levels can decrease by any amount (e.g. drop from 4 to 1)
|
||||
func Levelize(pages []Page) {
|
||||
var prevLevel uint64
|
||||
prevLevel = 1
|
||||
|
||||
for i := 0; i < len(pages); i++ {
|
||||
currLevel := pages[i].Level
|
||||
|
||||
// handle deprecated level value of 0
|
||||
if pages[i].Level == 0 {
|
||||
pages[i].Level = 1
|
||||
}
|
||||
|
||||
// first time thru
|
||||
if i == 0 {
|
||||
// first time thru
|
||||
pages[i].Level = 1
|
||||
prevLevel = 1
|
||||
continue
|
||||
}
|
||||
|
||||
if currLevel == prevLevel {
|
||||
// nothing doing
|
||||
continue
|
||||
}
|
||||
|
||||
if currLevel > prevLevel+1 {
|
||||
// bad data detected e.g. prevLevel=1 and pages[i].Level=3
|
||||
// so we re-level to pages[i].Level=2 and all child pages
|
||||
// and then increment i to correct point
|
||||
prevLevel++
|
||||
pages[i].Level = prevLevel
|
||||
|
||||
// safety check before entering loop and renumbering child pages
|
||||
if i+1 <= len(pages) {
|
||||
|
||||
for j := i + 1; j < len(pages); j++ {
|
||||
if pages[j].Level < prevLevel {
|
||||
i = j
|
||||
break
|
||||
}
|
||||
|
||||
if pages[j].Level == currLevel {
|
||||
pages[j].Level = prevLevel
|
||||
} else if (pages[j].Level - prevLevel) > 1 {
|
||||
currLevel = pages[j].Level
|
||||
prevLevel++
|
||||
pages[j].Level = prevLevel
|
||||
}
|
||||
|
||||
i = j
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
prevLevel = currLevel
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,4 +111,124 @@ func TestNumberize3(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// go test github.com/documize/community/core/model -run TestNumberize
|
||||
// Tests that numbering does not crash because of bad data
|
||||
func TestNumberize4(t *testing.T) {
|
||||
pages := []Page{}
|
||||
|
||||
pages = append(pages, Page{Level: 0, Sequence: 1000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 2000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 3000})
|
||||
|
||||
// corruption starts here with Level=3 instead of Level=2
|
||||
pages = append(pages, Page{Level: 3, Sequence: 4000})
|
||||
pages = append(pages, Page{Level: 4, Sequence: 4000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 5000})
|
||||
pages = append(pages, Page{Level: 2, Sequence: 6000})
|
||||
|
||||
Numberize(pages)
|
||||
|
||||
expecting := []string{
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"3.1",
|
||||
"3.1.1",
|
||||
// data below cannot be processed due to corruption
|
||||
"", // should be 4
|
||||
"1", // should be 5
|
||||
}
|
||||
|
||||
for i, p := range pages {
|
||||
if p.Numbering != expecting[i] {
|
||||
t.Errorf("(Test 4) Position %d: expecting %s got %s\n", i, expecting[i], p.Numbering)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that good level data is not messed with
|
||||
func TestLevelize1(t *testing.T) {
|
||||
pages := []Page{}
|
||||
|
||||
pages = append(pages, Page{Level: 1, Sequence: 1000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 2000})
|
||||
pages = append(pages, Page{Level: 2, Sequence: 3000})
|
||||
pages = append(pages, Page{Level: 3, Sequence: 4000})
|
||||
pages = append(pages, Page{Level: 4, Sequence: 5000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 6000})
|
||||
pages = append(pages, Page{Level: 2, Sequence: 7000})
|
||||
|
||||
Levelize(pages)
|
||||
|
||||
expecting := []uint64{1, 1, 2, 3, 4, 1, 2}
|
||||
|
||||
for i, p := range pages {
|
||||
if p.Level != expecting[i] {
|
||||
t.Errorf("(TestLevelize1) Position %d: expecting %d got %d (sequence: %f)\n", i+1, expecting[i], p.Level, p.Sequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that bad level data
|
||||
func TestLevelize2(t *testing.T) {
|
||||
pages := []Page{}
|
||||
|
||||
pages = append(pages, Page{Level: 1, Sequence: 1000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 2000})
|
||||
pages = append(pages, Page{Level: 3, Sequence: 3000})
|
||||
pages = append(pages, Page{Level: 3, Sequence: 4000})
|
||||
pages = append(pages, Page{Level: 4, Sequence: 5000})
|
||||
pages = append(pages, Page{Level: 1, Sequence: 6000})
|
||||
pages = append(pages, Page{Level: 2, Sequence: 7000})
|
||||
|
||||
Levelize(pages)
|
||||
|
||||
expecting := []uint64{1, 1, 2, 2, 3, 1, 2}
|
||||
|
||||
for i, p := range pages {
|
||||
if p.Level != expecting[i] {
|
||||
t.Errorf("(TestLevelize2) Position %d: expecting %d got %d (sequence: %f)\n", i+1, expecting[i], p.Level, p.Sequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLevelize3(t *testing.T) {
|
||||
pages := []Page{}
|
||||
|
||||
pages = append(pages, Page{Level: 1, Sequence: 1000})
|
||||
pages = append(pages, Page{Level: 4, Sequence: 2000})
|
||||
pages = append(pages, Page{Level: 5, Sequence: 3000})
|
||||
|
||||
Levelize(pages)
|
||||
|
||||
expecting := []uint64{1, 2, 3}
|
||||
|
||||
for i, p := range pages {
|
||||
if p.Level != expecting[i] {
|
||||
t.Errorf("(TestLevelize3) Position %d: expecting %d got %d (sequence: %f)\n", i+1, expecting[i], p.Level, p.Sequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLevelize4(t *testing.T) {
|
||||
pages := []Page{}
|
||||
|
||||
pages = append(pages, Page{Level: 1, Sequence: 1000})
|
||||
pages = append(pages, Page{Level: 4, Sequence: 2000})
|
||||
pages = append(pages, Page{Level: 5, Sequence: 3000})
|
||||
pages = append(pages, Page{Level: 5, Sequence: 4000})
|
||||
pages = append(pages, Page{Level: 6, Sequence: 5000})
|
||||
pages = append(pages, Page{Level: 6, Sequence: 6000})
|
||||
pages = append(pages, Page{Level: 2, Sequence: 7000})
|
||||
|
||||
Levelize(pages)
|
||||
|
||||
expecting := []uint64{1, 2, 3, 3, 4, 4, 2}
|
||||
|
||||
for i, p := range pages {
|
||||
if p.Level != expecting[i] {
|
||||
t.Errorf("(TestLevelize4) Position %d: expecting %d got %d (sequence: %f)\n", i+1, expecting[i], p.Level, p.Sequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// go test github.com/documize/community/core/model -run TestNumberiz, 3, 4, 4, 2e
|
||||
|
|
|
@ -16,23 +16,26 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/documize/community/model"
|
||||
"github.com/documize/community/model/workflow"
|
||||
)
|
||||
|
||||
// Page represents a section within a document.
|
||||
type Page struct {
|
||||
model.BaseEntity
|
||||
OrgID string `json:"orgId"`
|
||||
DocumentID string `json:"documentId"`
|
||||
UserID string `json:"userId"`
|
||||
ContentType string `json:"contentType"`
|
||||
PageType string `json:"pageType"`
|
||||
BlockID string `json:"blockId"`
|
||||
Level uint64 `json:"level"`
|
||||
Sequence float64 `json:"sequence"`
|
||||
Numbering string `json:"numbering"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Revisions uint64 `json:"revisions"`
|
||||
OrgID string `json:"orgId"`
|
||||
DocumentID string `json:"documentId"`
|
||||
UserID string `json:"userId"`
|
||||
ContentType string `json:"contentType"`
|
||||
PageType string `json:"pageType"`
|
||||
BlockID string `json:"blockId"`
|
||||
Level uint64 `json:"level"`
|
||||
Sequence float64 `json:"sequence"`
|
||||
Numbering string `json:"numbering"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Revisions uint64 `json:"revisions"`
|
||||
Status workflow.ChangeStatus `json:"status"`
|
||||
RelativeID string `json:"relativeId"` // links page to pending page edits
|
||||
}
|
||||
|
||||
// SetDefaults ensures no blank values.
|
||||
|
@ -41,6 +44,10 @@ func (p *Page) SetDefaults() {
|
|||
p.ContentType = "wysiwyg"
|
||||
}
|
||||
|
||||
if p.Level == 0 {
|
||||
p.Level = 1
|
||||
}
|
||||
|
||||
p.Title = strings.TrimSpace(p.Title)
|
||||
}
|
||||
|
||||
|
@ -114,3 +121,18 @@ type LevelRequest struct {
|
|||
PageID string `json:"pageId"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
// BulkRequest details page, it's meta, pending page changes.
|
||||
// Used to bulk load data by GUI so as to reduce network requests.
|
||||
type BulkRequest struct {
|
||||
Page Page `json:"page"`
|
||||
Meta Meta `json:"meta"`
|
||||
Pending []PendingPage `json:"pending"`
|
||||
}
|
||||
|
||||
// PendingPage details page that is yet to be published
|
||||
type PendingPage struct {
|
||||
Page Page `json:"page"`
|
||||
Meta Meta `json:"meta"`
|
||||
Owner string `json:"owner"`
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue