diff --git a/core/acl/aclservice.go b/core/acl/aclservice.go index 8f685a4d9..46f57c75b 100644 --- a/core/acl/aclservice.go +++ b/core/acl/aclservice.go @@ -114,7 +114,6 @@ func (a *aclService) Remove(ctx context.Context, spaceId string, identities []cr } func (a *aclService) CancelJoin(ctx context.Context, spaceId string) (err error) { - // TODO: finish this by implementing space offload for join canceled spaces (?) sp, err := a.spaceService.Get(ctx, spaceId) if err != nil { return err @@ -124,7 +123,7 @@ func (a *aclService) CancelJoin(ctx context.Context, spaceId string) (err error) if err != nil { return fmt.Errorf("%w, %w", ErrAclRequestFailed, err) } - return nil + return a.spaceService.Delete(ctx, spaceId) } func (a *aclService) Decline(ctx context.Context, spaceId string, identity crypto.PubKey) (err error) { @@ -248,7 +247,7 @@ func (a *aclService) Join(ctx context.Context, spaceId string, inviteCid cid.Cid return fmt.Errorf("unmarshal invite key: %w", err) } - err = a.joiningClient.RequestJoin(ctx, spaceId, list.RequestJoinPayload{ + aclHeadId, err := a.joiningClient.RequestJoin(ctx, spaceId, list.RequestJoinPayload{ InviteKey: inviteKey, Metadata: a.spaceService.AccountMetadataPayload(), }) @@ -262,7 +261,7 @@ func (a *aclService) Join(ctx context.Context, spaceId string, inviteCid cid.Cid } return fmt.Errorf("%w, %w", ErrAclRequestFailed, err) } - return a.spaceService.Join(ctx, spaceId) + return a.spaceService.Join(ctx, spaceId, aclHeadId) } type InviteView struct { diff --git a/core/space.go b/core/space.go index 678fe0aa6..fb2156dd6 100644 --- a/core/space.go +++ b/core/space.go @@ -164,10 +164,17 @@ func (mw *Middleware) SpaceStopSharing(cctx context.Context, req *pb.RpcSpaceSto } func (mw *Middleware) SpaceJoinCancel(cctx context.Context, req *pb.RpcSpaceJoinCancelRequest) *pb.RpcSpaceJoinCancelResponse { + aclService := mw.applicationService.GetApp().MustComponent(acl.CName).(acl.AclService) + err := aclService.CancelJoin(cctx, req.SpaceId) + code := mapErrorCode(err, + errToCode(space.ErrSpaceDeleted, pb.RpcSpaceJoinCancelResponseError_SPACE_IS_DELETED), + errToCode(space.ErrSpaceNotExists, pb.RpcSpaceJoinCancelResponseError_NO_SUCH_SPACE), + errToCode(acl.ErrAclRequestFailed, pb.RpcSpaceJoinCancelResponseError_REQUEST_FAILED), + ) return &pb.RpcSpaceJoinCancelResponse{ Error: &pb.RpcSpaceJoinCancelResponseError{ - Code: 1, - Description: getErrorDescription(fmt.Errorf("not implemented")), + Code: code, + Description: getErrorDescription(err), }, } } diff --git a/go.mod b/go.mod index 7f7577e8e..7bc617e6f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/VividCortex/ewma v1.2.0 github.com/adrium/goheif v0.0.0-20230113233934-ca402e77a786 - github.com/anyproto/any-sync v0.3.30 + github.com/anyproto/any-sync v0.3.31-0.20240229195757-a3f8fe1b2b2c github.com/anyproto/go-naturaldate/v2 v2.0.2-0.20230524105841-9829cfd13438 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/blevesearch/bleve/v2 v2.3.10 diff --git a/go.sum b/go.sum index 378ad0f5c..c7d93efd5 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,8 @@ github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/anyproto/any-sync v0.3.30 h1:mTZeYGkI9WzgCgbm1+gXRsKM8F8+BMPr8NM8sKgpzGk= github.com/anyproto/any-sync v0.3.30/go.mod h1:q7O3a4p3DwhFzIACjh6I6rv2RzgqPQesZNZv27B8Xdo= +github.com/anyproto/any-sync v0.3.31-0.20240229195757-a3f8fe1b2b2c h1:0iYicD26fh5jkHT8hLWCwcpAYK2TjWYwazOua0c2DSY= +github.com/anyproto/any-sync v0.3.31-0.20240229195757-a3f8fe1b2b2c/go.mod h1:q7O3a4p3DwhFzIACjh6I6rv2RzgqPQesZNZv27B8Xdo= github.com/anyproto/badger/v4 v4.2.1-0.20240110160636-80743fa3d580 h1:Ba80IlCCxkZ9H1GF+7vFu/TSpPvbpDCxXJ5ogc4euYc= github.com/anyproto/badger/v4 v4.2.1-0.20240110160636-80743fa3d580/go.mod h1:T/uWAYxrXdaXw64ihI++9RMbKTCpKd/yE9+saARew7k= github.com/anyproto/go-chash v0.1.0 h1:I9meTPjXFRfXZHRJzjOHC/XF7Q5vzysKkiT/grsogXY= diff --git a/space/internal/personalspace/personal.go b/space/internal/personalspace/personal.go index 268a1ca7c..35ab5e5eb 100644 --- a/space/internal/personalspace/personal.go +++ b/space/internal/personalspace/personal.go @@ -53,7 +53,7 @@ func (s *spaceController) Start(ctx context.Context) (err error) { err = s.loader.Start(ctx) // This could happen for old accounts if errors.Is(err, spaceloader.ErrSpaceNotExists) { - err = s.techSpace.SpaceViewCreate(ctx, s.spaceId, false, spaceinfo.AccountStatusUnknown) + err = s.techSpace.SpaceViewCreate(ctx, s.spaceId, false, spaceinfo.SpacePersistentInfo{AccountStatus: spaceinfo.AccountStatusUnknown}) if err != nil { return } diff --git a/space/internal/spaceprocess/joiner/joiner.go b/space/internal/spaceprocess/joiner/joiner.go index f1ba124c9..2e19c28fb 100644 --- a/space/internal/spaceprocess/joiner/joiner.go +++ b/space/internal/spaceprocess/joiner/joiner.go @@ -30,21 +30,41 @@ type Params struct { func New(app *app.App, params Params) Joiner { child := app.ChildApp() + params.Status.Lock() + joinHeadId := params.Status.LatestAclHeadId() + params.Status.Unlock() child.Register(params.Status). Register(newStatusChanger()). - Register(aclwaiter.New(params.SpaceId, func(acl list.AclList) error { - params.Status.Lock() - defer params.Status.Unlock() - err := params.Status.SetPersistentInfo(context.Background(), spaceinfo.SpacePersistentInfo{ - SpaceID: params.SpaceId, - AccountStatus: spaceinfo.AccountStatusActive, - AclHeadId: acl.Head().Id, - }) - if err != nil { - params.Log.Error("failed to set persistent status", zap.Error(err)) - } - return err - })) + Register(aclwaiter.New(params.SpaceId, + joinHeadId, + // onFinish + func(acl list.AclList) error { + params.Status.Lock() + defer params.Status.Unlock() + err := params.Status.SetPersistentInfo(context.Background(), spaceinfo.SpacePersistentInfo{ + SpaceID: params.SpaceId, + AccountStatus: spaceinfo.AccountStatusActive, + AclHeadId: acl.Head().Id, + }) + if err != nil { + params.Log.Error("failed to set persistent status", zap.Error(err)) + } + return err + }, + // onReject + func(acl list.AclList) error { + params.Status.Lock() + defer params.Status.Unlock() + err := params.Status.SetPersistentInfo(context.Background(), spaceinfo.SpacePersistentInfo{ + SpaceID: params.SpaceId, + AccountStatus: spaceinfo.AccountStatusDeleted, + AclHeadId: acl.Head().Id, + }) + if err != nil { + params.Log.Error("failed to set persistent status", zap.Error(err)) + } + return err + })) return &joiner{ app: child, } diff --git a/space/internal/techspace/techspace.go b/space/internal/techspace/techspace.go index 5fce78fa7..d95545905 100644 --- a/space/internal/techspace/techspace.go +++ b/space/internal/techspace/techspace.go @@ -42,7 +42,7 @@ type TechSpace interface { Close(ctx context.Context) (err error) TechSpaceId() string - SpaceViewCreate(ctx context.Context, spaceId string, force bool, status spaceinfo.AccountStatus) (err error) + SpaceViewCreate(ctx context.Context, spaceId string, force bool, info spaceinfo.SpacePersistentInfo) (err error) SpaceViewExists(ctx context.Context, spaceId string) (exists bool, err error) SetLocalInfo(ctx context.Context, info spaceinfo.SpaceLocalInfo) (err error) SetAccessType(ctx context.Context, spaceId string, acc spaceinfo.AccessType) (err error) @@ -136,9 +136,9 @@ func (s *techSpace) SetPersistentInfo(ctx context.Context, info spaceinfo.SpaceP }) } -func (s *techSpace) SpaceViewCreate(ctx context.Context, spaceId string, force bool, status spaceinfo.AccountStatus) (err error) { +func (s *techSpace) SpaceViewCreate(ctx context.Context, spaceId string, force bool, info spaceinfo.SpacePersistentInfo) (err error) { if force { - return s.spaceViewCreate(ctx, spaceId, status) + return s.spaceViewCreate(ctx, spaceId, info) } viewId, err := s.getViewIdLocked(ctx, spaceId) if err != nil { @@ -146,7 +146,7 @@ func (s *techSpace) SpaceViewCreate(ctx context.Context, spaceId string, force b } _, err = s.objectCache.GetObject(ctx, viewId) if err != nil { // TODO: check specific error - return s.spaceViewCreate(ctx, spaceId, status) + return s.spaceViewCreate(ctx, spaceId, info) } return ErrSpaceViewExists } @@ -173,14 +173,17 @@ func (s *techSpace) SpaceViewId(spaceId string) (string, error) { return s.getViewIdLocked(context.TODO(), spaceId) } -func (s *techSpace) spaceViewCreate(ctx context.Context, spaceID string, status spaceinfo.AccountStatus) (err error) { +func (s *techSpace) spaceViewCreate(ctx context.Context, spaceID string, info spaceinfo.SpacePersistentInfo) (err error) { uniqueKey, err := domain.NewUniqueKey(smartblock.SmartBlockTypeSpaceView, spaceID) if err != nil { return } initFunc := func(id string) *editorsb.InitContext { st := state.NewDoc(id, nil).(*state.State) - st.SetDetail(bundle.RelationKeySpaceAccountStatus.String(), pbtypes.Int64(int64(status))) + st.SetDetail(bundle.RelationKeySpaceAccountStatus.String(), pbtypes.Int64(int64(info.AccountStatus))) + if info.AclHeadId != "" { + st.SetDetail(bundle.RelationKeyLatestAclHeadId.String(), pbtypes.String(info.AclHeadId)) + } return &editorsb.InitContext{Ctx: ctx, SpaceID: s.techCore.Id(), State: st} } _, err = s.objectCache.DeriveTreeObject(ctx, objectcache.TreeDerivationParams{ diff --git a/space/internal/techspace/techspace_test.go b/space/internal/techspace/techspace_test.go index be8f4d560..15f2b79db 100644 --- a/space/internal/techspace/techspace_test.go +++ b/space/internal/techspace/techspace_test.go @@ -78,7 +78,7 @@ func TestTechSpace_SpaceViewCreate(t *testing.T) { fx.objectCache.EXPECT().GetObject(ctx, viewId).Return(nil, fmt.Errorf("not found")) fx.objectCache.EXPECT().DeriveTreeObject(ctx, mock.Anything).Return(view, nil) - require.NoError(t, fx.SpaceViewCreate(ctx, spaceId, false, spaceinfo.AccountStatusUnknown)) + require.NoError(t, fx.SpaceViewCreate(ctx, spaceId, false, spaceinfo.SpacePersistentInfo{AccountStatus: spaceinfo.AccountStatusUnknown})) }) t.Run("err spaceView exists", func(t *testing.T) { @@ -88,7 +88,7 @@ func TestTechSpace_SpaceViewCreate(t *testing.T) { fx.expectDeriveTreePayload(viewId) fx.objectCache.EXPECT().GetObject(ctx, viewId).Return(view, nil) - assert.EqualError(t, fx.SpaceViewCreate(ctx, spaceId, false, spaceinfo.AccountStatusUnknown), ErrSpaceViewExists.Error()) + assert.EqualError(t, fx.SpaceViewCreate(ctx, spaceId, false, spaceinfo.SpacePersistentInfo{AccountStatus: spaceinfo.AccountStatusUnknown}), ErrSpaceViewExists.Error()) }) } diff --git a/space/join.go b/space/join.go index a5e73bba2..6fad481d1 100644 --- a/space/join.go +++ b/space/join.go @@ -7,7 +7,7 @@ import ( "github.com/anyproto/anytype-heart/space/spaceinfo" ) -func (s *service) Join(ctx context.Context, id string) error { +func (s *service) Join(ctx context.Context, id, aclHeadId string) error { s.mu.Lock() waiter, exists := s.waiting[id] if exists { @@ -23,6 +23,7 @@ func (s *service) Join(ctx context.Context, id string) error { return ctrl.SetInfo(ctx, spaceinfo.SpacePersistentInfo{ SpaceID: id, AccountStatus: spaceinfo.AccountStatusJoining, + AclHeadId: aclHeadId, }) } return nil @@ -32,7 +33,7 @@ func (s *service) Join(ctx context.Context, id string) error { wait: wait, } s.mu.Unlock() - ctrl, err := s.factory.CreateInvitingSpace(ctx, id) + ctrl, err := s.factory.CreateInvitingSpace(ctx, id, aclHeadId) if err != nil { s.mu.Lock() close(wait) diff --git a/space/service.go b/space/service.go index ff480aefb..fd803dd1e 100644 --- a/space/service.go +++ b/space/service.go @@ -49,7 +49,7 @@ type isNewAccount interface { type Service interface { Create(ctx context.Context) (space clientspace.Space, err error) - Join(ctx context.Context, id string) (err error) + Join(ctx context.Context, id, aclHeadId string) error CancelLeave(ctx context.Context, id string) (err error) Get(ctx context.Context, id string) (space clientspace.Space, err error) Delete(ctx context.Context, id string) (err error) diff --git a/space/spacefactory/spacefactory.go b/space/spacefactory/spacefactory.go index 4677ee321..e3c52b562 100644 --- a/space/spacefactory/spacefactory.go +++ b/space/spacefactory/spacefactory.go @@ -29,7 +29,7 @@ type SpaceFactory interface { NewShareableSpace(ctx context.Context, id string, info spaceinfo.SpacePersistentInfo) (spacecontroller.SpaceController, error) CreateMarketplaceSpace(ctx context.Context) (sp spacecontroller.SpaceController, err error) CreateAndSetTechSpace(ctx context.Context) (*clientspace.TechSpace, error) - CreateInvitingSpace(ctx context.Context, id string) (sp spacecontroller.SpaceController, err error) + CreateInvitingSpace(ctx context.Context, id, aclHeadId string) (sp spacecontroller.SpaceController, err error) } const CName = "client.space.spacefactory" @@ -74,7 +74,7 @@ func (s *spaceFactory) CreatePersonalSpace(ctx context.Context, metadata []byte) if err != nil { return } - if err := s.techSpace.SpaceViewCreate(ctx, coreSpace.Id(), true, spaceinfo.AccountStatusUnknown); err != nil { + if err := s.techSpace.SpaceViewCreate(ctx, coreSpace.Id(), true, spaceinfo.SpacePersistentInfo{AccountStatus: spaceinfo.AccountStatusUnknown}); err != nil { if errors.Is(err, techspace.ErrSpaceViewExists) { return s.NewPersonalSpace(ctx, metadata) } @@ -131,17 +131,23 @@ func (s *spaceFactory) NewShareableSpace(ctx context.Context, id string, info sp return ctrl, err } -func (s *spaceFactory) CreateInvitingSpace(ctx context.Context, id string) (sp spacecontroller.SpaceController, err error) { +func (s *spaceFactory) CreateInvitingSpace(ctx context.Context, id, aclHeadId string) (sp spacecontroller.SpaceController, err error) { exists, err := s.techSpace.SpaceViewExists(ctx, id) if err != nil { return } if !exists { - if err := s.techSpace.SpaceViewCreate(ctx, id, true, spaceinfo.AccountStatusJoining); err != nil { + if err := s.techSpace.SpaceViewCreate(ctx, id, true, spaceinfo.SpacePersistentInfo{ + AccountStatus: spaceinfo.AccountStatusJoining, + AclHeadId: aclHeadId, + }); err != nil { return nil, err } } - ctrl, err := shareablespace.NewSpaceController(id, spaceinfo.SpacePersistentInfo{SpaceID: id, AccountStatus: spaceinfo.AccountStatusJoining}, s.app) + ctrl, err := shareablespace.NewSpaceController(id, spaceinfo.SpacePersistentInfo{ + SpaceID: id, + AccountStatus: spaceinfo.AccountStatusJoining, + }, s.app) if err != nil { return nil, err } @@ -154,7 +160,7 @@ func (s *spaceFactory) CreateShareableSpace(ctx context.Context, id string) (sp if err != nil { return } - if err := s.techSpace.SpaceViewCreate(ctx, id, true, spaceinfo.AccountStatusUnknown); err != nil { + if err := s.techSpace.SpaceViewCreate(ctx, id, true, spaceinfo.SpacePersistentInfo{AccountStatus: spaceinfo.AccountStatusUnknown}); err != nil { return nil, err } ctrl, err := shareablespace.NewSpaceController(id, spaceinfo.SpacePersistentInfo{SpaceID: id, AccountStatus: spaceinfo.AccountStatusUnknown}, s.app)