1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-10 18:10:49 +09:00

Merge pull request #1560 from anyproto/go-3814-add-origin-to-files-via-reviser

GO-3814 Add recommendedRelations value revision for system types
This commit is contained in:
Kirill Stonozhenko 2024-09-10 16:09:24 +03:00 committed by GitHub
commit 931222e994
Signed by: github
GPG key ID: B5690EEEBB952194
5 changed files with 139 additions and 5 deletions

View file

@ -9,7 +9,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
)
const TypeChecksum = "745e40062786ba9e43273b0009612a02af1eb9920ecaf6fab191f86b5cdd33f3"
const TypeChecksum = "8b79add6b322acbcee123ad178c1aee523a2d9b9f219c391903530b29e554a1e"
const (
TypePrefix = "_ot"
)
@ -54,6 +54,7 @@ var (
Readonly: true,
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeyArtist), MustGetRelationLink(RelationKeyAudioAlbum), MustGetRelationLink(RelationKeyAudioAlbumTrackNumber), MustGetRelationLink(RelationKeyAudioGenre), MustGetRelationLink(RelationKeyAudioLyrics), MustGetRelationLink(RelationKeyReleasedYear), MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
RestrictObjectCreation: true,
Revision: 1,
Types: []model.SmartBlockType{model.SmartBlockType_File},
Url: TypePrefix + "audio",
},
@ -144,6 +145,7 @@ var (
Readonly: true,
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
RestrictObjectCreation: true,
Revision: 1,
Types: []model.SmartBlockType{model.SmartBlockType_File},
Url: TypePrefix + "file",
},
@ -167,6 +169,7 @@ var (
Readonly: true,
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeyWidthInPixels), MustGetRelationLink(RelationKeyCamera), MustGetRelationLink(RelationKeyHeightInPixels), MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyCameraIso), MustGetRelationLink(RelationKeyAperture), MustGetRelationLink(RelationKeyExposure), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFocalRatio), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
RestrictObjectCreation: true,
Revision: 1,
Types: []model.SmartBlockType{model.SmartBlockType_File},
Url: TypePrefix + "image",
},
@ -351,6 +354,7 @@ var (
Readonly: true,
RelationLinks: []*model.RelationLink{MustGetRelationLink(RelationKeySizeInBytes), MustGetRelationLink(RelationKeyFileMimeType), MustGetRelationLink(RelationKeyCamera), MustGetRelationLink(RelationKeyHeightInPixels), MustGetRelationLink(RelationKeyWidthInPixels), MustGetRelationLink(RelationKeyCameraIso), MustGetRelationLink(RelationKeyAperture), MustGetRelationLink(RelationKeyExposure), MustGetRelationLink(RelationKeyAddedDate), MustGetRelationLink(RelationKeyFileExt), MustGetRelationLink(RelationKeyOrigin)},
RestrictObjectCreation: true,
Revision: 1,
Types: []model.SmartBlockType{model.SmartBlockType_File},
Url: TypePrefix + "video",
},

View file

@ -156,7 +156,8 @@
"origin"
],
"description": "The recording of moving visual images",
"restrictObjectCreation": true
"restrictObjectCreation": true,
"revision": 1
},
{
"id": "dashboard",
@ -358,7 +359,8 @@
"origin"
],
"description": "A representation of the external form of a person or thing in art",
"restrictObjectCreation": true
"restrictObjectCreation": true,
"revision": 1
},
{
"id": "profile",
@ -398,7 +400,8 @@
"origin"
],
"description": "Sound when recorded, with ability to reproduce",
"restrictObjectCreation": true
"restrictObjectCreation": true,
"revision": 1
},
{
"id": "goal",
@ -435,7 +438,8 @@
"origin"
],
"description": "Computer resource for recording data in a computer storage device",
"restrictObjectCreation": true
"restrictObjectCreation": true,
"revision": 1
},
{
"id": "project",

View file

@ -4,9 +4,11 @@ import (
"context"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/domain"
)
type SpaceWithCtx interface {
DoCtx(ctx context.Context, objectId string, apply func(sb smartblock.SmartBlock) error) error
Id() string
DeriveObjectID(ctx context.Context, uniqueKey domain.UniqueKey) (id string, err error)
}

View file

@ -4,8 +4,10 @@ import (
"context"
"errors"
"fmt"
"strings"
"github.com/anyproto/any-sync/app/logger"
"github.com/ethereum/go-ethereum/log"
"github.com/gogo/protobuf/types"
"github.com/samber/lo"
"go.uber.org/zap"
@ -20,6 +22,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/internal/components/dependencies"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
type detailsSettable interface {
@ -100,6 +103,16 @@ func reviseSystemObject(ctx context.Context, log logger.CtxLogger, space depende
return false, nil
}
details := buildDiffDetails(marketObject, localObject)
recRelsDetail, err := checkRecommendedRelations(ctx, space, marketObject, localObject)
if err != nil {
log.Error("failed to check recommended relations", zap.Error(err))
}
if recRelsDetail != nil {
details = append(details, recRelsDetail)
}
if len(details) != 0 {
log.Debug("updating system object", zap.String("source", source), zap.String("space", space.Id()))
if err := space.DoCtx(ctx, pbtypes.GetString(localObject, bundle.RelationKeyId.String()), func(sb smartblock.SmartBlock) error {
@ -150,3 +163,44 @@ func buildDiffDetails(origin, current *types.Struct) (details []*model.Detail) {
}
return
}
func checkRecommendedRelations(ctx context.Context, space dependencies.SpaceWithCtx, origin, current *types.Struct) (newValue *model.Detail, err error) {
localIds := pbtypes.GetStringList(current, bundle.RelationKeyRecommendedRelations.String())
bundledIds := pbtypes.GetStringList(origin, bundle.RelationKeyRecommendedRelations.String())
newIds := make([]string, 0, len(bundledIds))
for _, bundledId := range bundledIds {
if !strings.HasPrefix(bundledId, addr.BundledRelationURLPrefix) {
return nil, fmt.Errorf("invalid recommended bundled relation id: %s. %s prefix is expected",
bundledId, addr.BundledRelationURLPrefix)
}
key := strings.TrimPrefix(bundledId, addr.BundledRelationURLPrefix)
uk, err := domain.NewUniqueKey(coresb.SmartBlockTypeRelation, key)
if err != nil {
return nil, err
}
// we should add only system relations to object types, because non-system could be not installed to space yet
if !lo.Contains(bundle.SystemRelations, domain.RelationKey(uk.InternalKey())) {
log.Debug("recommended relation is not system, so we are not adding it to the type object", zap.String("relation key", key))
continue
}
id, err := space.DeriveObjectID(ctx, uk)
if err != nil {
return nil, fmt.Errorf("failed to derive recommended relation with key '%s': %w", key, err)
}
newIds = append(newIds, id)
}
_, added := slice.DifferenceRemovedAdded(localIds, newIds)
if len(added) == 0 {
return nil, nil
}
return &model.Detail{
Key: bundle.RelationKeyRecommendedRelations.String(),
Value: pbtypes.StringList(append(localIds, added...)),
}, nil
}

View file

@ -9,7 +9,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
mock_space "github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
@ -217,4 +219,72 @@ func TestReviseSystemObject(t *testing.T) {
assert.NoError(t, err)
assert.True(t, toRevise)
})
t.Run("recommendedRelations list is updated", func(t *testing.T) {
// given
rel := &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyRevision.String(): pbtypes.Int64(1),
bundle.RelationKeySourceObject.String(): pbtypes.String("_otpage"),
bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-page"),
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{"rel-name"}),
}}
space := mock_space.NewMockSpace(t)
space.EXPECT().DoCtx(mock.Anything, mock.Anything, mock.Anything).Times(1).Return(nil)
space.EXPECT().Id().Times(1).Return("")
space.EXPECT().DeriveObjectID(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key domain.UniqueKey) (string, error) {
return addr.ObjectTypeKeyToIdPrefix + key.InternalKey(), nil
}).Maybe()
// when
marketObjects["_otpage"].Fields["recommendedRelations"] = pbtypes.StringList([]string{"_brname", "_brorigin"})
toRevise, err := reviseSystemObject(ctx, log, space, rel, marketObjects)
// then
assert.NoError(t, err)
assert.True(t, toRevise)
})
t.Run("recommendedRelations list is not updated", func(t *testing.T) {
// given
rel := &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyRevision.String(): pbtypes.Int64(2),
bundle.RelationKeySourceObject.String(): pbtypes.String("_otpage"),
bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-page"),
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{"rel-name", "rel-tag"}),
}}
space := mock_space.NewMockSpace(t)
space.EXPECT().DeriveObjectID(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key domain.UniqueKey) (string, error) {
return addr.ObjectTypeKeyToIdPrefix + key.InternalKey(), nil
}).Maybe()
// when
marketObjects["_otpage"].Fields["recommendedRelations"] = pbtypes.StringList([]string{"_brname", "_brtag"})
toRevise, err := reviseSystemObject(ctx, log, space, rel, marketObjects)
// then
assert.NoError(t, err)
assert.False(t, toRevise)
})
t.Run("recommendedRelations list is updated by not system relations", func(t *testing.T) {
// given
rel := &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyRevision.String(): pbtypes.Int64(2),
bundle.RelationKeySourceObject.String(): pbtypes.String("_otpage"),
bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-page"),
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{"rel-name"}),
}}
space := mock_space.NewMockSpace(t)
space.EXPECT().DeriveObjectID(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key domain.UniqueKey) (string, error) {
return addr.ObjectTypeKeyToIdPrefix + key.InternalKey(), nil
}).Maybe()
// when
marketObjects["_otpage"].Fields["recommendedRelations"] = pbtypes.StringList([]string{"_brname", "_brtag"})
toRevise, err := reviseSystemObject(ctx, log, space, rel, marketObjects)
// then
assert.NoError(t, err)
assert.False(t, toRevise)
})
}