MCPcopy Index your code
hub / github.com/bytebase/bytebase / ListWorkspacesByEmail

Method ListWorkspacesByEmail

backend/store/workspace.go:280–350  ·  view source on GitHub ↗

ListWorkspacesByEmail finds all workspaces where the given email is a member in the workspace IAM policy bindings, either directly or via a group. Returns workspaces sorted by name.

(ctx context.Context, find *FindWorkspaceMessage)

Source from the content-addressed store, hash-verified

278// in the workspace IAM policy bindings, either directly or via a group.
279// Returns workspaces sorted by name.
280func (s *Store) ListWorkspacesByEmail(ctx context.Context, find *FindWorkspaceMessage) ([]*WorkspaceMessage, error) {
281 memberName := common.FormatUserEmail(find.Email)
282
283 // Check direct membership OR group membership:
284 // 1. Direct: member = 'users/{email}'
285 // 2. Group: member = 'groups/{groupEmail}' and user_group with that email
286 // contains 'users/{email}' in its payload.members[].member
287 // 3. AllUsers: member = 'allUsers' (self-hosted only)
288 memberFilter := qb.Q().Space("member = ?", memberName)
289 memberFilter.Or(`member LIKE 'groups/%' AND EXISTS (
290 SELECT 1
291 FROM user_group ug,
292 jsonb_array_elements(ug.payload->'members') AS gm
293 WHERE ug.workspace = w.resource_id
294 AND ('groups/' || ug.email = member OR 'groups/' || ug.id = member)
295 AND gm->>'member' = ?
296 )`, memberName)
297 if find.IncludeAllUser {
298 memberFilter.Or("member = ?", common.AllUsers)
299 }
300
301 q := qb.Q().Space(`
302 SELECT DISTINCT w.resource_id, w.payload, w.created_at
303 FROM workspace w
304 JOIN policy p ON p.workspace = w.resource_id
305 WHERE p.resource_type = ?
306 AND p.type = ?
307 AND w.deleted = FALSE
308 AND EXISTS (
309 SELECT 1
310 FROM jsonb_array_elements(p.payload->'bindings') AS binding,
311 jsonb_array_elements_text(binding->'members') AS member
312 WHERE ?
313 )
314 `, storepb.Policy_WORKSPACE.String(), storepb.Policy_IAM.String(), memberFilter)
315 if v := find.WorkspaceID; v != nil {
316 q.And("w.resource_id = ?", *v)
317 }
318 q.Space("ORDER BY w.created_at")
319
320 query, args, err := q.ToSQL()
321 if err != nil {
322 return nil, errors.Wrapf(err, "failed to build sql")
323 }
324
325 rows, err := s.GetDB().QueryContext(ctx, query, args...)
326 if err != nil {
327 return nil, errors.Wrap(err, "failed to find workspaces by member")
328 }
329 defer rows.Close()
330
331 var workspaces []*WorkspaceMessage
332 for rows.Next() {
333 var ws WorkspaceMessage
334 var payloadBytes []byte
335 var createdAt any
336 if err := rows.Scan(&ws.ResourceID, &payloadBytes, &createdAt); err != nil {
337 return nil, errors.Wrap(err, "failed to scan workspace")

Callers 2

FindWorkspaceMethod · 0.95
ListWorkspacesMethod · 0.80

Calls 13

GetDBMethod · 0.95
FormatUserEmailFunction · 0.92
QFunction · 0.92
SpaceMethod · 0.80
OrMethod · 0.80
AndMethod · 0.80
ToSQLMethod · 0.80
QueryContextMethod · 0.80
ScanMethod · 0.80
UnmarshalMethod · 0.80
StringMethod · 0.65
CloseMethod · 0.65

Tested by

no test coverage detected