diff --git a/data/document.go b/data/document.go index ca52f7f5..908479d3 100644 --- a/data/document.go +++ b/data/document.go @@ -28,7 +28,7 @@ type Document struct { type UpdateResult int const ( - UpdateResultNoAction = iota + UpdateResultNoAction UpdateResult = iota UpdateResultAppend UpdateResultRebuild ) @@ -56,6 +56,7 @@ func NewDocument( func (d *Document) Update(changes ...*threadmodels.RawChange) (DocumentState, UpdateResult, error) { var treeChanges []*Change + var foundACLChange bool for _, ch := range changes { aclChange, err := d.treeBuilder.makeVerifiedACLChange(ch) if err != nil { @@ -71,13 +72,14 @@ func (d *Document) Update(changes ...*threadmodels.RawChange) (DocumentState, Up if err != nil { return nil, UpdateResultNoAction, fmt.Errorf("change with id %s cannot be added: %w", ch.Id, err) } + if treeChange.IsACLChange() { + foundACLChange = true + } } - for _, ch := range treeChanges { - if ch.IsACLChange() { - res, err := d.Build() - return res, UpdateResultRebuild, err - } + if foundACLChange { + res, err := d.Build() + return res, UpdateResultRebuild, err } prevHeads := d.docContext.fullTree.Heads() @@ -92,11 +94,28 @@ func (d *Document) Update(changes ...*threadmodels.RawChange) (DocumentState, Up break } + // decrypting everything, because we have no new keys + for _, ch := range treeChanges { + if ch.Content.GetChangesData() != nil { + key, exists := d.docContext.aclState.userReadKeys[ch.Content.CurrentReadKeyHash] + if !exists { + err := fmt.Errorf("failed to find key with hash: %d", ch.Content.CurrentReadKeyHash) + return nil, UpdateResultNoAction, err + } + + err := ch.DecryptContents(key) + if err != nil { + err = fmt.Errorf("failed to decrypt contents for hash: %d", ch.Content.CurrentReadKeyHash) + return nil, UpdateResultNoAction, err + } + } + } + // because for every new change we know it was after any of the previous heads // each of previous heads must have same "Next" nodes // so it doesn't matter which one we choose // so we choose first one - newState, err := d.docStateBuilder.appendFrom(prevHeads[0]) + newState, err := d.docStateBuilder.appendFrom(prevHeads[0], d.docContext.docState) if err != nil { res, _ := d.Build() return res, UpdateResultRebuild, fmt.Errorf("could not add changes to state, rebuilded") diff --git a/data/document_test.go b/data/document_test.go index b3abc82b..6cd128a6 100644 --- a/data/document_test.go +++ b/data/document_test.go @@ -26,3 +26,28 @@ func TestDocument_Build(t *testing.T) { st := res.(*PlainTextDocumentState) assert.Equal(t, st.Text, "some text|first") } + +func TestDocument_Update(t *testing.T) { + thread, err := threadbuilder.NewThreadBuilderFromFile("threadbuilder/userjoinexample.yml") + if err != nil { + t.Fatal(err) + } + keychain := thread.GetKeychain() + accountData := &AccountData{ + Identity: keychain.GetIdentity("A"), + EncKey: keychain.EncryptionKeys["A"], + } + doc := NewDocument(thread, NewPlainTextDocumentStateProvider(), accountData) + res, err := doc.Build() + if err != nil { + t.Fatal(err) + } + + st := res.(*PlainTextDocumentState) + assert.Equal(t, st.Text, "some text|first") + + rawChs := thread.GetUpdatedChanges() + res, updateResult, err := doc.Update(rawChs...) + assert.Equal(t, updateResult, UpdateResultAppend) + assert.Equal(t, res.(*PlainTextDocumentState).Text, "some text|first|second") +} diff --git a/data/documentstatebuilder.go b/data/documentstatebuilder.go index c0ca38e9..241c3acc 100644 --- a/data/documentstatebuilder.go +++ b/data/documentstatebuilder.go @@ -63,8 +63,12 @@ func (d *documentStateBuilder) build() (s DocumentState, err error) { return s, err } -func (d *documentStateBuilder) appendFrom(fromId string) (s DocumentState, err error) { +func (d *documentStateBuilder) appendFrom(fromId string, init DocumentState) (s DocumentState, err error) { + s = init d.tree.Iterate(fromId, func(c *Change) (isContinue bool) { + if c.Id == fromId { + return true + } if c.DecryptedDocumentChange != nil { s, err = s.ApplyChange(c.DecryptedDocumentChange, c.Id) if err != nil { diff --git a/data/threadbuilder/userjoinexample.yml b/data/threadbuilder/userjoinexample.yml index 59e32c01..02092a8a 100644 --- a/data/threadbuilder/userjoinexample.yml +++ b/data/threadbuilder/userjoinexample.yml @@ -106,7 +106,7 @@ updatedChanges: identity: B changes: - textAppend: - text: "first" + text: "second" readKey: key.Read.1 updatedGraph: - id: B.1.3