chore: add /groups endpoint to filter by organization and/or member (#14260)

* chore: merge get groups sql queries into 1

* Add endpoint for fetching groups with filters
* remove 2 ways to customizing a fake authorizer
This commit is contained in:
Steven Masley
2024-08-15 13:40:15 -05:00
committed by GitHub
parent 83ccdaa755
commit 7b09d98238
24 changed files with 539 additions and 289 deletions

View File

@ -9,13 +9,11 @@ import (
"github.com/google/uuid"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/coderd"
"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/db2sdk"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/codersdk"
)
@ -394,28 +392,65 @@ func (api *API) group(rw http.ResponseWriter, r *http.Request) {
// @Success 200 {array} codersdk.Group
// @Router /organizations/{organization}/groups [get]
func (api *API) groupsByOrganization(rw http.ResponseWriter, r *http.Request) {
org := httpmw.OrganizationParam(r)
values := r.URL.Query()
values.Set("organization", org.ID.String())
r.URL.RawQuery = values.Encode()
api.groups(rw, r)
}
// @Summary Get groups
// @ID get-groups
// @Security CoderSessionToken
// @Produce json
// @Tags Enterprise
// @Param organization query string true "Organization ID or name"
// @Param has_member query string true "User ID or name"
// @Success 200 {array} codersdk.Group
// @Router /groups [get]
func (api *API) groups(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
org = httpmw.OrganizationParam(r)
)
ctx := r.Context()
groups, err := api.Database.GetGroupsByOrganizationID(ctx, org.ID)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
httpapi.InternalServerError(rw, err)
var filter database.GetGroupsParams
parser := httpapi.NewQueryParamParser()
// Organization selector can be an org ID or name
filter.OrganizationID = parser.UUIDorName(r.URL.Query(), uuid.Nil, "organization", func(orgName string) (uuid.UUID, error) {
org, err := api.Database.GetOrganizationByName(ctx, orgName)
if err != nil {
return uuid.Nil, xerrors.Errorf("organization %q not found", orgName)
}
return org.ID, nil
})
// has_member selector can be a user ID or username
filter.HasMemberID = parser.UUIDorName(r.URL.Query(), uuid.Nil, "has_member", func(username string) (uuid.UUID, error) {
user, err := api.Database.GetUserByEmailOrUsername(ctx, database.GetUserByEmailOrUsernameParams{
Username: username,
Email: "",
})
if err != nil {
return uuid.Nil, xerrors.Errorf("user %q not found", username)
}
return user.ID, nil
})
parser.ErrorExcessParams(r.URL.Query())
if len(parser.Errors) > 0 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Query parameters have invalid values.",
Validations: parser.Errors,
})
return
}
// Filter groups based on rbac permissions
groups, err = coderd.AuthorizeFilter(api.AGPL.HTTPAuth, r, policy.ActionRead, groups)
groups, err := api.Database.GetGroups(ctx, filter)
if httpapi.Is404Error(err) {
httpapi.ResourceNotFound(rw)
return
}
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching groups.",
Detail: err.Error(),
})
httpapi.InternalServerError(rw, err)
return
}