@@ -227,6 +227,7 @@ func Workspaces(ctx context.Context, db database.Store, query string, page coder
227
227
filter .OrganizationID = parseOrganization (ctx ,db ,parser ,values ,"organization" )
228
228
filter .Shared = parser .NullableBoolean (values , sql.NullBool {},"shared" )
229
229
filter .SharedWithUserID = parseUser (ctx ,db ,parser ,values ,"shared_with_user" )
230
+ filter .SharedWithGroupID = parseGroup (ctx ,db ,parser ,values ,"shared_with_group" )
230
231
231
232
type paramMatch struct {
232
233
name string
@@ -383,6 +384,65 @@ func parseUser(ctx context.Context, db database.Store, parser *httpapi.QueryPara
383
384
})
384
385
}
385
386
387
+ // Attempts to parse the filter into either the group ID, or the organization
388
+ // name and group name in the format of either <group name> which assumes the
389
+ // user's default, or <organization name>/<group name> returning the fetched
390
+ // group's ID.
391
+ func parseGroup (ctx context.Context ,db database.Store ,parser * httpapi.QueryParamParser ,vals url.Values ,queryParam string ) uuid.UUID {
392
+ return httpapi .ParseCustom (parser ,vals ,uuid .Nil ,queryParam ,func (v string ) (uuid.UUID ,error ) {
393
+ if v == "" {
394
+ return uuid .Nil ,nil
395
+ }
396
+ groupID ,err := uuid .Parse (v )
397
+ if err == nil {
398
+ return groupID ,nil
399
+ }
400
+
401
+ var groupName string
402
+ var org database.Organization
403
+ parts := strings .Split (v ,"/" )
404
+ switch len (parts ) {
405
+ case 1 :
406
+ dbOrg ,err := db .GetDefaultOrganization (ctx )
407
+ if err != nil {
408
+ return uuid .Nil ,xerrors .New ("fetching default organization" )
409
+ }
410
+ org = dbOrg
411
+ groupName = parts [0 ]
412
+ case 2 :
413
+ orgName := parts [0 ]
414
+ if err := codersdk .NameValid (orgName );err != nil {
415
+ return uuid .Nil ,xerrors .Errorf ("invalid organization name %w" ,err )
416
+ }
417
+ dbOrg ,err := db .GetOrganizationByName (ctx , database.GetOrganizationByNameParams {
418
+ Name :orgName ,
419
+ })
420
+ if err != nil {
421
+ return uuid .Nil ,xerrors .Errorf ("organization %q either does not exist, or you are unauthorized to view it" ,orgName )
422
+ }
423
+ org = dbOrg
424
+
425
+ groupName = parts [1 ]
426
+
427
+ default :
428
+ return uuid .Nil ,xerrors .New ("invalid organization or group name, the filter must be in the pattern of <organization name>/<group name>" )
429
+ }
430
+
431
+ if err := codersdk .GroupNameValid (groupName );err != nil {
432
+ return uuid .Nil ,xerrors .Errorf ("invalid group name %w" ,err )
433
+ }
434
+
435
+ group ,err := db .GetGroupByOrgAndName (ctx , database.GetGroupByOrgAndNameParams {
436
+ OrganizationID :org .ID ,
437
+ Name :groupName ,
438
+ })
439
+ if err != nil {
440
+ return uuid .Nil ,xerrors .Errorf ("group %q either does not exist, does not belong to the organization %q, or you are unauthorized to view it" ,groupName ,org .Name )
441
+ }
442
+ return group .ID ,nil
443
+ })
444
+ }
445
+
386
446
// splitQueryParameterByDelimiter takes a query string and splits it into the individual elements
387
447
// of the query. Each element is separated by a delimiter. All quoted strings are
388
448
// kept as a single element.