Skip to content

chore: remove organization requirement from convertGroup() #12195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: convertGroups() no longer requires organization info
Removing role information from some users in the api. This info is
excessive and not required. It is costly to always include
  • Loading branch information
Emyrk committed Feb 16, 2024
commit a1457b590cbed0d75cd993060e2df076b046c55b
18 changes: 11 additions & 7 deletions coderd/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,17 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs

if dblog.UserUsername.Valid {
user = &codersdk.User{
ID: dblog.UserID,
Username: dblog.UserUsername.String,
Email: dblog.UserEmail.String,
CreatedAt: dblog.UserCreatedAt.Time,
Status: codersdk.UserStatus(dblog.UserStatus.UserStatus),
Roles: []codersdk.Role{},
AvatarURL: dblog.UserAvatarUrl.String,
ReducedUser: codersdk.ReducedUser{
MinimalUser: codersdk.MinimalUser{
ID: dblog.UserID,
Username: dblog.UserUsername.String,
AvatarURL: dblog.UserAvatarUrl.String,
},
Email: dblog.UserEmail.String,
CreatedAt: dblog.UserCreatedAt.Time,
Status: codersdk.UserStatus(dblog.UserStatus.UserStatus),
},
Roles: []codersdk.Role{},
}

for _, roleName := range dblog.UserRoles {
Expand Down
76 changes: 56 additions & 20 deletions coderd/database/db2sdk/db2sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ import (
"github.com/coder/coder/v2/tailnet"
)

// List is a helper function to reduce boilerplate when converting slices of
// database types to slices of codersdk types.
// Only works if the function takes a single argument.
func List[F any, T any](list []F, convert func(F) T) []T {
into := make([]T, 0, len(list))
for _, item := range list {
into = append(into, convert(item))
}
return into
}

type ExternalAuthMeta struct {
Authenticated bool
ValidateError string
Expand All @@ -49,21 +60,17 @@ func ExternalAuth(auth database.ExternalAuthLink, meta ExternalAuthMeta) codersd
}
}

func WorkspaceBuildParameters(params []database.WorkspaceBuildParameter) []codersdk.WorkspaceBuildParameter {
out := make([]codersdk.WorkspaceBuildParameter, len(params))
for i, p := range params {
out[i] = WorkspaceBuildParameter(p)
}
return out
}

func WorkspaceBuildParameter(p database.WorkspaceBuildParameter) codersdk.WorkspaceBuildParameter {
return codersdk.WorkspaceBuildParameter{
Name: p.Name,
Value: p.Value,
}
}

func WorkspaceBuildParameters(params []database.WorkspaceBuildParameter) []codersdk.WorkspaceBuildParameter {
return List(params, WorkspaceBuildParameter)
}

func TemplateVersionParameters(params []database.TemplateVersionParameter) ([]codersdk.TemplateVersionParameter, error) {
out := make([]codersdk.TemplateVersionParameter, len(params))
var err error
Expand Down Expand Up @@ -118,21 +125,33 @@ func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk
}, nil
}

func User(user database.User, organizationIDs []uuid.UUID) codersdk.User {
convertedUser := codersdk.User{
ID: user.ID,
func ReducedUser(user database.User) codersdk.ReducedUser {
return codersdk.ReducedUser{
MinimalUser: codersdk.MinimalUser{
ID: user.ID,
Username: user.Username,
AvatarURL: user.AvatarURL,
},
Email: user.Email,
Name: user.Name,
CreatedAt: user.CreatedAt,
LastSeenAt: user.LastSeenAt,
Username: user.Username,
Status: codersdk.UserStatus(user.Status),
OrganizationIDs: organizationIDs,
Roles: make([]codersdk.Role, 0, len(user.RBACRoles)),
AvatarURL: user.AvatarURL,
LoginType: codersdk.LoginType(user.LoginType),
ThemePreference: user.ThemePreference,
}
}

func ReducedUsers(users []database.User) []codersdk.ReducedUser {
return List(users, ReducedUser)
}

func User(user database.User, organizationIDs []uuid.UUID) codersdk.User {
convertedUser := codersdk.User{
ReducedUser: ReducedUser(user),
OrganizationIDs: organizationIDs,
Roles: make([]codersdk.Role, 0, len(user.RBACRoles)),
}

for _, roleName := range user.RBACRoles {
rbacRole, _ := rbac.RoleByName(roleName)
Expand All @@ -142,6 +161,25 @@ func User(user database.User, organizationIDs []uuid.UUID) codersdk.User {
return convertedUser
}

func Users(users []database.User, organizationIDs map[uuid.UUID][]uuid.UUID) []codersdk.User {
return List(users, func(user database.User) codersdk.User {
return User(user, organizationIDs[user.ID])
})
}

func Group(group database.Group, members []database.User) codersdk.Group {
return codersdk.Group{
ID: group.ID,
Name: group.Name,
DisplayName: group.DisplayName,
OrganizationID: group.OrganizationID,
AvatarURL: group.AvatarURL,
Members: ReducedUsers(members),
QuotaAllowance: int(group.QuotaAllowance),
Source: codersdk.GroupSource(group.Source),
}
}

func Role(role rbac.Role) codersdk.Role {
return codersdk.Role{
DisplayName: role.DisplayName,
Expand Down Expand Up @@ -248,11 +286,9 @@ func OAuth2ProviderApp(accessURL *url.URL, dbApp database.OAuth2ProviderApp) cod
}

func OAuth2ProviderApps(accessURL *url.URL, dbApps []database.OAuth2ProviderApp) []codersdk.OAuth2ProviderApp {
apps := []codersdk.OAuth2ProviderApp{}
for _, dbApp := range dbApps {
apps = append(apps, OAuth2ProviderApp(accessURL, dbApp))
}
return apps
return List(dbApps, func(dbApp database.OAuth2ProviderApp) codersdk.OAuth2ProviderApp {
return OAuth2ProviderApp(accessURL, dbApp)
})
}

func convertDisplayApps(apps []database.DisplayApp) []codersdk.DisplayApp {
Expand Down
16 changes: 8 additions & 8 deletions codersdk/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ type CreateGroupRequest struct {
}

type Group struct {
ID uuid.UUID `json:"id" format:"uuid"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
Members []User `json:"members"`
AvatarURL string `json:"avatar_url"`
QuotaAllowance int `json:"quota_allowance"`
Source GroupSource `json:"source"`
ID uuid.UUID `json:"id" format:"uuid"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
Members []ReducedUser `json:"members"`
AvatarURL string `json:"avatar_url"`
QuotaAllowance int `json:"quota_allowance"`
Source GroupSource `json:"source"`
}

func (g Group) IsEveryone() bool {
Expand Down
4 changes: 2 additions & 2 deletions codersdk/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ type UpdateTemplateACL struct {
// ACLAvailable is a list of users and groups that can be added to a template
// ACL.
type ACLAvailable struct {
Users []User `json:"users"`
Groups []Group `json:"groups"`
Users []ReducedUser `json:"users"`
Groups []Group `json:"groups"`
}

type UpdateTemplateMeta struct {
Expand Down
23 changes: 15 additions & 8 deletions codersdk/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,28 @@ type MinimalUser struct {
AvatarURL string `json:"avatar_url" format:"uri"`
}

// User represents a user in Coder.
type User struct {
ID uuid.UUID `json:"id" validate:"required" table:"id" format:"uuid"`
Username string `json:"username" validate:"required" table:"username,default_sort"`
// ReducedUser omits role and organization information. Roles are deduced from
// the user's site and organization roles. This requires fetching the user's
// organizational memberships. Fetching that is more expensive, and not usually
// required by the frontend.
type ReducedUser struct {
MinimalUser
Name string `json:"name"`
Email string `json:"email" validate:"required" table:"email" format:"email"`
CreatedAt time.Time `json:"created_at" validate:"required" table:"created at" format:"date-time"`
LastSeenAt time.Time `json:"last_seen_at" format:"date-time"`

Status UserStatus `json:"status" table:"status" enums:"active,suspended"`
Status UserStatus `json:"status" table:"status" enums:"active,suspended"`
LoginType LoginType `json:"login_type"`
ThemePreference string `json:"theme_preference"`
}

// User represents a user in Coder.
type User struct {
ReducedUser

OrganizationIDs []uuid.UUID `json:"organization_ids" format:"uuid"`
Roles []Role `json:"roles"`
AvatarURL string `json:"avatar_url" format:"uri"`
LoginType LoginType `json:"login_type"`
ThemePreference string `json:"theme_preference"`
}

type GetUsersResponse struct {
Expand Down
69 changes: 5 additions & 64 deletions enterprise/coderd/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"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"
Expand Down Expand Up @@ -77,7 +78,7 @@ func (api *API) postGroupByOrganization(rw http.ResponseWriter, r *http.Request)
var emptyUsers []database.User
aReq.New = group.Auditable(emptyUsers)

httpapi.Write(ctx, rw, http.StatusCreated, convertGroup(group, nil))
httpapi.Write(ctx, rw, http.StatusCreated, db2sdk.Group(group, nil))
}

// @Summary Update group by name
Expand Down Expand Up @@ -281,7 +282,7 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {

aReq.New = group.Auditable(patchedMembers)

httpapi.Write(ctx, rw, http.StatusOK, convertGroup(group, patchedMembers))
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Group(group, patchedMembers))
}

// @Summary Delete group by name
Expand Down Expand Up @@ -365,7 +366,7 @@ func (api *API) group(rw http.ResponseWriter, r *http.Request) {
return
}

httpapi.Write(ctx, rw, http.StatusOK, convertGroup(group, users))
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Group(group, users))
}

// @Summary Get groups by organization
Expand Down Expand Up @@ -410,68 +411,8 @@ func (api *API) groups(rw http.ResponseWriter, r *http.Request) {
return
}

resp = append(resp, convertGroup(group, members))
resp = append(resp, db2sdk.Group(group, members))
}

httpapi.Write(ctx, rw, http.StatusOK, resp)
}

func convertGroup(g database.Group, users []database.User) codersdk.Group {
// It's ridiculous to query all the orgs of a user here
// especially since as of the writing of this comment there
// is only one org. So we pretend everyone is only part of
// the group's organization.
orgs := make(map[uuid.UUID][]uuid.UUID)
for _, user := range users {
orgs[user.ID] = []uuid.UUID{g.OrganizationID}
}

return codersdk.Group{
ID: g.ID,
Name: g.Name,
DisplayName: g.DisplayName,
OrganizationID: g.OrganizationID,
AvatarURL: g.AvatarURL,
QuotaAllowance: int(g.QuotaAllowance),
Members: convertUsers(users, orgs),
Source: codersdk.GroupSource(g.Source),
}
}

func convertUser(user database.User, organizationIDs []uuid.UUID) codersdk.User {
convertedUser := codersdk.User{
ID: user.ID,
Email: user.Email,
CreatedAt: user.CreatedAt,
LastSeenAt: user.LastSeenAt,
Username: user.Username,
Status: codersdk.UserStatus(user.Status),
OrganizationIDs: organizationIDs,
Roles: make([]codersdk.Role, 0, len(user.RBACRoles)),
AvatarURL: user.AvatarURL,
LoginType: codersdk.LoginType(user.LoginType),
}

for _, roleName := range user.RBACRoles {
rbacRole, _ := rbac.RoleByName(roleName)
convertedUser.Roles = append(convertedUser.Roles, convertRole(rbacRole))
}

return convertedUser
}

func convertUsers(users []database.User, organizationIDsByUserID map[uuid.UUID][]uuid.UUID) []codersdk.User {
converted := make([]codersdk.User, 0, len(users))
for _, u := range users {
userOrganizationIDs := organizationIDsByUserID[u.ID]
converted = append(converted, convertUser(u, userOrganizationIDs))
}
return converted
}

func convertRole(role rbac.Role) codersdk.Role {
return codersdk.Role{
DisplayName: role.DisplayName,
Name: role.Name,
}
}
10 changes: 5 additions & 5 deletions enterprise/coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"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/database/dbauthz"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
Expand Down Expand Up @@ -64,15 +65,14 @@ func (api *API) templateAvailablePermissions(rw http.ResponseWriter, r *http.Req
return
}

sdkGroups = append(sdkGroups, convertGroup(group, members))
sdkGroups = append(sdkGroups, db2sdk.Group(group, members))
}

httpapi.Write(ctx, rw, http.StatusOK, codersdk.ACLAvailable{
// No need to pass organization info here.
// TODO: @emyrk we should return a MinimalUser here instead of a full user.
// The FE requires the `email` field, so this cannot be done without
// a UI change.
Users: convertUsers(users, map[uuid.UUID][]uuid.UUID{}),
Users: db2sdk.ReducedUsers(users),
Groups: sdkGroups,
})
}
Expand Down Expand Up @@ -134,7 +134,7 @@ func (api *API) templateACL(rw http.ResponseWriter, r *http.Request) {
return
}
groups = append(groups, codersdk.TemplateGroup{
Group: convertGroup(group.Group, members),
Group: db2sdk.Group(group.Group, members),
Role: convertToTemplateRole(group.Actions),
})
}
Expand Down Expand Up @@ -287,7 +287,7 @@ func convertTemplateUsers(tus []database.TemplateUser, orgIDsByUserIDs map[uuid.

for _, tu := range tus {
users = append(users, codersdk.TemplateUser{
User: convertUser(tu.User, orgIDsByUserIDs[tu.User.ID]),
User: db2sdk.User(tu.User, orgIDsByUserIDs[tu.User.ID]),
Role: convertToTemplateRole(tu.Actions),
})
}
Expand Down
2 changes: 1 addition & 1 deletion enterprise/coderd/userauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ func TestGroupSync(t *testing.T) {
}

for _, group := range orgGroups {
userInGroup := slice.ContainsCompare(group.Members, codersdk.User{Email: user.Email}, func(a, b codersdk.User) bool {
userInGroup := slice.ContainsCompare(group.Members, codersdk.ReducedUser{Email: user.Email}, func(a, b codersdk.ReducedUser) bool {
return a.Email == b.Email
})
if group.IsEveryone() {
Expand Down