MCPcopy Create free account
hub / github.com/PerpetualSoftware/pad / checkItemVisible

Method checkItemVisible

internal/server/server.go:2131–2239  ·  view source on GitHub ↗

checkItemVisible is the context-free visibility decision. Returns (true, nil) when the (user, role) pair can see `item` under the same rules `requireItemVisible` enforces. Centralizes the rule set so the resolver route (IDEA-1492) and the middleware-gated handlers can't drift. Inputs: - workspaceI

(workspaceID string, item *models.Item, user *models.User, role string, isBearer bool)

Source from the content-addressed store, hash-verified

2129// because the item-grants branch only checked direct grants + the
2130// member's explicit collection-access list).
2131func (s *Server) checkItemVisible(workspaceID string, item *models.Item, user *models.User, role string, isBearer bool) (bool, error) {
2132 // Tokenized-nil-user bypass. RequireWorkspaceAccess synthesizes
2133 // "owner" on fresh installs (UserCount == 0, currentUser == nil) and
2134 // "editor" for legacy workspace-scoped API tokens (currentUser ==
2135 // nil but tokenWorkspaceID matches). Both are authorized by the
2136 // middleware already. Real authenticated users with these roles
2137 // (workspace owners, member.Role=="editor", …) must NOT short-circuit
2138 // here — they have to walk the per-collection filter so
2139 // collection_access="specific" + member_collection_access actually
2140 // gates them (Codex round-3 — the round-2 fix dropped the
2141 // `user == nil` qualifier and accidentally disabled the gate for
2142 // every real editor too).
2143 if user == nil && (role == "owner" || role == "editor") {
2144 return true, nil
2145 }
2146 if user == nil {
2147 return false, nil
2148 }
2149 // Admin sees everything, but only for cookie-session auth (matches
2150 // visibleCollectionIDs's nil-filter shape). Bearer-borne admins
2151 // (BUG-1918) fall through to the same per-collection filter every
2152 // other member faces.
2153 if user.Role == "admin" && !isBearer {
2154 return true, nil
2155 }
2156
2157 // Visibility filter: nil = unrestricted; non-nil = restricted to the slice.
2158 visibleIDs, err := s.store.VisibleCollectionIDs(workspaceID, user.ID)
2159 if err != nil {
2160 return false, err
2161 }
2162 if !isCollectionVisible(item.CollectionID, visibleIDs) {
2163 return false, nil
2164 }
2165
2166 // Replay guestResourceFilterCore's logic without the *http.Request
2167 // dependency. Member-with-all-access short-circuits to "no item-level
2168 // filter"; guests + restricted members get the grant filter.
2169 if role != "guest" {
2170 member, err := s.store.GetWorkspaceMember(workspaceID, user.ID)
2171 if err != nil {
2172 return false, err
2173 }
2174 if member != nil && (member.CollectionAccess == "all" || member.CollectionAccess == "") {
2175 // Full collection access — visibleIDs filter already passed.
2176 return true, nil
2177 }
2178 }
2179
2180 grantCollIDs, grantedItemIDs, err := s.store.GuestVisibleResources(workspaceID, user.ID)
2181 if err != nil {
2182 return false, err
2183 }
2184 if len(grantedItemIDs) == 0 {
2185 // No item-level grants in play. visibleCollectionIDs already
2186 // determined the collection is reachable; visibility stands.
2187 return true, nil
2188 }

Calls 6

isCollectionVisibleFunction · 0.85
VisibleCollectionIDsMethod · 0.80
GetWorkspaceMemberMethod · 0.80
GuestVisibleResourcesMethod · 0.80