diff --git a/core/block/chats/service.go b/core/block/chats/service.go index 563480bb8..5ca82792b 100644 --- a/core/block/chats/service.go +++ b/core/block/chats/service.go @@ -90,7 +90,13 @@ func (s *service) SubscribeToMessagePreviews(ctx context.Context) (string, error s.lock.Lock() if s.chatObjectsSubQueue != nil { s.lock.Unlock() - return chatobject.LastMessageSubscriptionId, nil + + err := s.UnsubscribeFromMessagePreviews() + if err != nil { + return "", fmt.Errorf("stop previous subscription: %w", err) + } + + s.lock.Lock() } s.chatObjectsSubQueue = mb.New[*pb.EventMessage](0) s.lock.Unlock() diff --git a/core/block/editor/accountobject/accountobject.go b/core/block/editor/accountobject/accountobject.go index 1f64d9b9c..32fbd2f67 100644 --- a/core/block/editor/accountobject/accountobject.go +++ b/core/block/editor/accountobject/accountobject.go @@ -169,16 +169,16 @@ func (a *accountObject) Init(ctx *smartblock.InitContext) error { return fmt.Errorf("insert account document: %w", err) } } - st := a.NewState() - err = a.update(a.ctx, st) + + err = a.update(a.ctx, ctx.State) if err != nil { return fmt.Errorf("update state: %w", err) } - err = a.initState(st) + err = a.initState(ctx.State) if err != nil { return fmt.Errorf("init state: %w", err) } - return a.SmartBlock.Apply(st, smartblock.NotPushChanges, smartblock.NoHistory, smartblock.SkipIfNoChanges) + return a.SmartBlock.Apply(ctx.State, smartblock.NotPushChanges, smartblock.NoHistory, smartblock.SkipIfNoChanges) } func (a *accountObject) genInitialDoc() (builder *storestate.Builder, err error) { diff --git a/core/block/editor/smartblock/detailsinject.go b/core/block/editor/smartblock/detailsinject.go index 689ba7455..a9b56603d 100644 --- a/core/block/editor/smartblock/detailsinject.go +++ b/core/block/editor/smartblock/detailsinject.go @@ -27,7 +27,6 @@ func (sb *smartBlock) injectLocalDetails(s *state.State) error { localDetailsFromStore := details.CopyOnlyKeys(keys...) localDetailsFromStore.Delete(bundle.RelationKeyResolvedLayout) - s.InjectLocalDetails(localDetailsFromStore) if p := s.ParentState(); p != nil && !hasPendingLocalDetails { // inject for both current and parent state @@ -229,68 +228,74 @@ func (sb *smartBlock) resolveLayout(s *state.State) { } var ( - layoutValue = s.Details().Get(bundle.RelationKeyLayout) - currentValue = s.LocalDetails().Get(bundle.RelationKeyResolvedLayout) - newValue domain.Value + layoutValue = s.Details().Get(bundle.RelationKeyLayout) + currentValue = s.LocalDetails().Get(bundle.RelationKeyResolvedLayout) + newValue domain.Value + fallbackValue = domain.Int64(int64(model.ObjectType_basic)) ) - defer func() { - if newValue.Ok() { - s.SetDetailAndBundledRelation(bundle.RelationKeyResolvedLayout, newValue) + if !currentValue.Ok() && layoutValue.Ok() { + // we don't have resolvedLayout in local details, but we have layout + currentValue = layoutValue + } + + if len(s.ObjectTypeKeys()) > 0 { + if bt, err := bundle.GetType(s.ObjectTypeKeys()[len(s.ObjectTypeKeys())-1]); err == nil { + fallbackValue = domain.Int64(int64(bt.Layout)) } - convertLayoutFromNote(s, currentValue, newValue) - }() + } typeDetails, err := sb.getTypeDetails(s) if err != nil { - if layoutValue.Ok() { - newValue = layoutValue - } else if !currentValue.Ok() { - log.Errorf("failed to get recommended layout from details of type: %v. Fallback to basic layout", err) - newValue = domain.Int64(int64(model.ObjectType_basic)) - } - return + log.Debugf("failed to get type details: %v", err) } valueInType := typeDetails.Get(bundle.RelationKeyRecommendedLayout) - - if s.ObjectTypeKey() == bundle.TypeKeyTemplate { - if layoutValue.Ok() { - newValue = layoutValue - } else if valueInType.Ok() { - newValue = valueInType - } else if !currentValue.Ok() { - log.Errorf("failed to get recommended layout from details of type: %v. Fallback to basic layout", err) - newValue = domain.Int64(int64(model.ObjectType_basic)) - } - return - } - - if valueInType.Ok() { - newValue = valueInType - } else if layoutValue.Ok() { + if layoutValue.Ok() { newValue = layoutValue - } else if !currentValue.Ok() { - log.Errorf("failed to get recommended layout from details of type: %v. Fallback to basic layout", err) - newValue = domain.Int64(int64(model.ObjectType_basic)) + } else if valueInType.Ok() { + newValue = valueInType + } else if currentValue.Ok() { + newValue = currentValue + } else { + log.Warnf("failed to get recommended layout from details of type: %v. Fallback to basic layout", err) + newValue = fallbackValue } + + if newValue.Ok() { + s.SetDetailAndBundledRelation(bundle.RelationKeyResolvedLayout, newValue) + } + + convertLayoutBlocks(s, currentValue, newValue) } -func convertLayoutFromNote(st *state.State, oldLayout, newLayout domain.Value) { - if !newLayout.Ok() || newLayout.Int64() == int64(model.ObjectType_note) { +func convertLayoutBlocks(st *state.State, oldLayout, newLayout domain.Value) { + if !newLayout.Ok() { return } - if oldLayout.Ok() && oldLayout.Int64() != int64(model.ObjectType_note) { + if oldLayout.Equal(newLayout) { return } - if !oldLayout.Ok() { - // absence of Title block means that object has Note layout + if newLayout.Int64() != int64(model.ObjectType_note) { title := st.Pick(state.TitleBlockID) if title != nil { return } + log.With("objectId", st.RootId()).Infof("convert layout: %s -> %s", oldLayout, newLayout) + template.InitTemplate(st, template.WithNameFromFirstBlock, template.WithTitle) + } else if newLayout.Int64() == int64(model.ObjectType_note) { + title := st.Pick(state.TitleBlockID) + if title == nil { + return + } + + log.With("objectId", st.RootId()).Infof("convert layout: %s -> %s", oldLayout, newLayout) + template.InitTemplate(st, + template.WithNameToFirstBlock, + template.WithNoTitle, + template.WithNoDescription, + ) } - template.InitTemplate(st, template.WithNameFromFirstBlock, template.WithTitle) } func (sb *smartBlock) getTypeDetails(s *state.State) (*domain.Details, error) { diff --git a/core/block/restriction/object.go b/core/block/restriction/object.go index d2df616bb..c9a5e82f4 100644 --- a/core/block/restriction/object.go +++ b/core/block/restriction/object.go @@ -175,8 +175,6 @@ var ( bundle.TypeKeySet, bundle.TypeKeyCollection, // lists bundle.TypeKeyFile, bundle.TypeKeyAudio, bundle.TypeKeyVideo, bundle.TypeKeyImage, // files } - - deletableSystemTypes = []domain.TypeKey{bundle.TypeKeyTask, bundle.TypeKeyNote} ) func GetRestrictionsBySBType(sbType smartblock.SmartBlockType) []int { @@ -264,8 +262,6 @@ func getRestrictionsForUniqueKey(uk domain.UniqueKey) (r ObjectRestrictions) { if slices.Contains(bundle.SystemTypes, domain.TypeKey(key)) { if slices.Contains(editableSystemTypes, domain.TypeKey(key)) { r = sysTypesRestrictions - } else if slices.Contains(deletableSystemTypes, domain.TypeKey(key)) { - r = objRestrictEditAndTemplate } else { r = sysTypesRestrictionsEdit } diff --git a/core/files/fileuploader/uploader.go b/core/files/fileuploader/uploader.go index 5775ccb39..b8c21398e 100644 --- a/core/files/fileuploader/uploader.go +++ b/core/files/fileuploader/uploader.go @@ -441,7 +441,12 @@ func (u *uploader) Upload(ctx context.Context) (result UploadResult) { u.fileStyle = u.block.Model().GetFile().GetStyle() } if !u.forceType { - u.fileType = u.detectType(buf) + fileType, detectErr := u.detectType(buf) + if detectErr != nil { + err = fmt.Errorf("detectType: %w", detectErr) + return + } + u.fileType = fileType } if u.fileStyle == model.BlockContentFile_Auto { if u.fileType == model.BlockContentFile_File || u.fileType == model.BlockContentFile_None { @@ -539,13 +544,17 @@ func (u *uploader) getOrCreateFileObject(ctx context.Context, addResult *files.A } -func (u *uploader) detectType(buf *fileReader) model.BlockContentFileType { +func (u *uploader) detectType(buf *fileReader) (model.BlockContentFileType, error) { mime, err := mimetype.DetectReader(buf) + _, seekErr := buf.Seek(0, io.SeekStart) + if seekErr != nil { + return 0, fmt.Errorf("seek: %w", err) + } if err != nil { log.With("error", err).Error("detect MIME") - return model.BlockContentFile_File + return model.BlockContentFile_File, nil } - return file.DetectTypeByMIME(u.name, mime.String()) + return file.DetectTypeByMIME(u.name, mime.String()), nil } type FileComponent interface { diff --git a/core/indexer/reindex.go b/core/indexer/reindex.go index 6acb6a379..8e790e843 100644 --- a/core/indexer/reindex.go +++ b/core/indexer/reindex.go @@ -27,7 +27,7 @@ import ( const ( // ForceObjectsReindexCounter reindex thread-based objects - ForceObjectsReindexCounter int32 = 17 + ForceObjectsReindexCounter int32 = 18 // ForceFilesReindexCounter reindex file objects ForceFilesReindexCounter int32 = 12 // diff --git a/pkg/lib/bundle/systemTypes.gen.go b/pkg/lib/bundle/systemTypes.gen.go index 2e233fbc9..befbaedeb 100644 --- a/pkg/lib/bundle/systemTypes.gen.go +++ b/pkg/lib/bundle/systemTypes.gen.go @@ -6,14 +6,12 @@ package bundle import domain "github.com/anyproto/anytype-heart/core/domain" -const SystemTypesChecksum = "bf5fb329802ba479e21c98306b1bda3226c17c6cae83b280ede6954d9c012185" +const SystemTypesChecksum = "a1a53bd06364104221da62efd98227afede5c8074dd3a5be71db7c6e24810a26" // SystemTypes contains types that have some special biz logic depends on them in some objects // they shouldn't be removed or edited in any way var SystemTypes = append(InternalTypes, []domain.TypeKey{ TypeKeyPage, - TypeKeyNote, - TypeKeyTask, TypeKeyCollection, TypeKeySet, TypeKeyBookmark, diff --git a/pkg/lib/bundle/systemTypes.json b/pkg/lib/bundle/systemTypes.json index bd0534f6f..7dcdbe24b 100644 --- a/pkg/lib/bundle/systemTypes.json +++ b/pkg/lib/bundle/systemTypes.json @@ -13,8 +13,6 @@ "date", "template", "page", - "note", - "task", "collection", "set", "bookmark", diff --git a/space/clientspace/space.go b/space/clientspace/space.go index cbbd29511..4de7d9659 100644 --- a/space/clientspace/space.go +++ b/space/clientspace/space.go @@ -164,11 +164,10 @@ func (s *space) tryLoadBundledAndInstallIfMissing(disableRemoteLoad bool) { if errors.Is(err, context.Canceled) { return // we are closing, skip installation, } - log.Error("failed to load bundled objects", zap.Error(err)) + log.Warn("failed to load bundled objects", zap.Error(err)) } - _, _, err = s.installer.InstallBundledObjects(s.loadMissingBundledObjectsCtx, s, missingSourceIds, true) - if err != nil { - log.Error("failed to install bundled objects", zap.Error(err)) + if len(missingSourceIds) > 0 { + log.Warn("missing bundled objects", zap.Strings("ids", missingSourceIds)) } } @@ -187,9 +186,7 @@ func (s *space) mandatoryObjectsLoad(ctx context.Context, disableRemoteLoad bool return } go s.tryLoadBundledAndInstallIfMissing(disableRemoteLoad) - if s.loadMandatoryObjectsErr != nil { - return - } + err := s.migrationProfileObject(ctx) if err != nil { log.Error("failed to migrate profile object", zap.Error(err)) diff --git a/util/builtinobjects/data/empty.zip b/util/builtinobjects/data/empty.zip index 3e108f451..ff5a9480e 100644 Binary files a/util/builtinobjects/data/empty.zip and b/util/builtinobjects/data/empty.zip differ