Skip to content

Commit

Permalink
fix missing visibility rules applied to direct node reads
Browse files Browse the repository at this point in the history
  • Loading branch information
Southclaws committed Oct 10, 2024
1 parent 73f373b commit f8646bf
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 18 deletions.
41 changes: 27 additions & 14 deletions app/resources/library/node_querier/node_querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ func New(db *ent.Client) *Querier {
}

type options struct {
withChildren bool
visibilityRules bool
requestingAccount *account.AccountID
}

type Option func(*options)

func WithChildren(accountID *account.AccountID) Option {
// WithVisibilityRulesApplied ensures ownership and visibility rules are applied
// if not set the default behaviour is no rules applied, all nodes are returned.
func WithVisibilityRulesApplied(accountID *account.AccountID) Option {
return func(o *options) {
o.withChildren = true
o.visibilityRules = true
o.requestingAccount = accountID
}
}
Expand Down Expand Up @@ -63,8 +65,19 @@ func (q *Querier) Get(ctx context.Context, qk library.QueryKey, opts ...Option)
})
})

if o.withChildren {
query.WithNodes(func(cq *ent.NodeQuery) {
if o.visibilityRules {
if o.requestingAccount == nil {
query.Where(node.VisibilityEQ(node.VisibilityPublished))
} else {
query.Where(node.Or(
node.AccountID(xid.ID(*o.requestingAccount)),
node.VisibilityEQ(node.VisibilityPublished),
))
}
}

query.WithNodes(func(cq *ent.NodeQuery) {
if o.visibilityRules {
// Apply visibility rules:
// - published nodes are visible to everyone
// - non-published nodes are not visible to anyone except the owner
Expand All @@ -76,15 +89,15 @@ func (q *Querier) Get(ctx context.Context, qk library.QueryKey, opts ...Option)
node.VisibilityEQ(node.VisibilityPublished),
))
}

cq.
WithAssets().
WithOwner(func(aq *ent.AccountQuery) {
aq.WithAccountRoles(func(arq *ent.AccountRolesQuery) { arq.WithRole() })
}).
Order(node.ByUpdatedAt(sql.OrderDesc()), node.ByCreatedAt(sql.OrderDesc()))
})
}
}

cq.
WithAssets().
WithOwner(func(aq *ent.AccountQuery) {
aq.WithAccountRoles(func(arq *ent.AccountRolesQuery) { arq.WithRole() })
}).
Order(node.ByUpdatedAt(sql.OrderDesc()), node.ByCreatedAt(sql.OrderDesc()))
})

col, err := query.Only(ctx)
if err != nil {
Expand Down
9 changes: 5 additions & 4 deletions app/services/library/node_read/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/rs/xid"
"go.uber.org/zap"

"github.com/Southclaws/storyden/app/resources/account"
"github.com/Southclaws/storyden/app/resources/datagraph/semdex"
"github.com/Southclaws/storyden/app/resources/library"
"github.com/Southclaws/storyden/app/resources/library/node_querier"
Expand Down Expand Up @@ -43,9 +42,11 @@ func (q *HydratedQuerier) GetBySlug(ctx context.Context, qk library.QueryKey) (*

opts := []node_querier.Option{}

session.Call(func(acc account.Account) {
opts = append(opts, node_querier.WithChildren(&acc.ID))
})
if s, ok := session.Get(); ok {
opts = append(opts, node_querier.WithVisibilityRulesApplied(&s.ID))
} else {
opts = append(opts, node_querier.WithVisibilityRulesApplied(nil))
}

n, err := q.nodereader.Get(ctx, qk, opts...)
if err != nil {
Expand Down
19 changes: 19 additions & 0 deletions tests/library/visibility/visibility_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,25 @@ func TestNodesVisibility(t *testing.T) {
a.NotContains(ids, node2.JSON200.Id, "guest cannot see node2 as it is not published")
a.NotContains(ids, node3.JSON200.Id, "guest cannot see node3 as it is not published")
})

t.Run("visibility_non_published_non_owner_404", func(t *testing.T) {
t.Parallel()

published := openapi.Published
draft := openapi.Draft

node1 := tests.AssertRequest(cl.NodeCreateWithResponse(root, openapi.NodeInitialProps{Name: "n1", Slug: opt.New(uuid.NewString()).Ptr(), Visibility: &published}, adminSession))(t, http.StatusOK)
node2 := tests.AssertRequest(cl.NodeCreateWithResponse(root, openapi.NodeInitialProps{Name: "n2", Slug: opt.New(uuid.NewString()).Ptr(), Visibility: &draft, Parent: &node1.JSON200.Slug}, authorSession))(t, http.StatusOK)

get1asAuthor, err := cl.NodeGetWithResponse(root, node2.JSON200.Slug, authorSession)
tests.Ok(t, err, get1asAuthor)

get1asRando, err := cl.NodeGetWithResponse(root, node2.JSON200.Slug, randoSession)
tests.Status(t, err, get1asRando, http.StatusNotFound)

get1asGuest, err := cl.NodeGetWithResponse(root, node2.JSON200.Slug)
tests.Status(t, err, get1asGuest, http.StatusNotFound)
})
}))
}))
}

0 comments on commit f8646bf

Please sign in to comment.