diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index 32b1e427e2..77b280ff7b 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -223,6 +223,7 @@ func UserFromGroupMember(member database.GroupMember) database.User { QuietHoursSchedule: member.UserQuietHoursSchedule, Name: member.UserName, GithubComUserID: member.UserGithubComUserID, + IsServiceAccount: member.UserIsServiceAccount, } } @@ -251,6 +252,7 @@ func UserFromGroupMemberRow(member database.GetGroupMembersByGroupIDPaginatedRow QuietHoursSchedule: member.UserQuietHoursSchedule, Name: member.UserName, GithubComUserID: member.UserGithubComUserID, + IsServiceAccount: member.UserIsServiceAccount, } } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index f1b7f3763b..3a77928e1f 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1619,6 +1619,7 @@ CREATE VIEW group_members_expanded AS users.name AS user_name, users.github_com_user_id AS user_github_com_user_id, users.is_system AS user_is_system, + users.is_service_account AS user_is_service_account, groups.organization_id, groups.name AS group_name, all_members.group_id @@ -1627,8 +1628,6 @@ CREATE VIEW group_members_expanded AS JOIN groups ON ((groups.id = all_members.group_id))) WHERE (users.deleted = false); -COMMENT ON VIEW group_members_expanded IS 'Joins group members with user information, organization ID, group name. Includes both regular group members and organization members (as part of the "Everyone" group).'; - CREATE TABLE inbox_notifications ( id uuid NOT NULL, user_id uuid NOT NULL, diff --git a/coderd/database/migrations/000448_group_member_is_service_account.down.sql b/coderd/database/migrations/000448_group_member_is_service_account.down.sql new file mode 100644 index 0000000000..1e890d92da --- /dev/null +++ b/coderd/database/migrations/000448_group_member_is_service_account.down.sql @@ -0,0 +1,35 @@ +DROP VIEW group_members_expanded; + +CREATE VIEW group_members_expanded AS + WITH all_members AS ( + SELECT group_members.user_id, + group_members.group_id + FROM group_members + UNION + SELECT organization_members.user_id, + organization_members.organization_id AS group_id + FROM organization_members + ) + SELECT users.id AS user_id, + users.email AS user_email, + users.username AS user_username, + users.hashed_password AS user_hashed_password, + users.created_at AS user_created_at, + users.updated_at AS user_updated_at, + users.status AS user_status, + users.rbac_roles AS user_rbac_roles, + users.login_type AS user_login_type, + users.avatar_url AS user_avatar_url, + users.deleted AS user_deleted, + users.last_seen_at AS user_last_seen_at, + users.quiet_hours_schedule AS user_quiet_hours_schedule, + users.name AS user_name, + users.github_com_user_id AS user_github_com_user_id, + users.is_system AS user_is_system, + groups.organization_id, + groups.name AS group_name, + all_members.group_id + FROM ((all_members + JOIN users ON ((users.id = all_members.user_id))) + JOIN groups ON ((groups.id = all_members.group_id))) + WHERE (users.deleted = false); diff --git a/coderd/database/migrations/000448_group_member_is_service_account.up.sql b/coderd/database/migrations/000448_group_member_is_service_account.up.sql new file mode 100644 index 0000000000..f843cd7fbe --- /dev/null +++ b/coderd/database/migrations/000448_group_member_is_service_account.up.sql @@ -0,0 +1,36 @@ +DROP VIEW group_members_expanded; + +CREATE VIEW group_members_expanded AS + WITH all_members AS ( + SELECT group_members.user_id, + group_members.group_id + FROM group_members + UNION + SELECT organization_members.user_id, + organization_members.organization_id AS group_id + FROM organization_members + ) + SELECT users.id AS user_id, + users.email AS user_email, + users.username AS user_username, + users.hashed_password AS user_hashed_password, + users.created_at AS user_created_at, + users.updated_at AS user_updated_at, + users.status AS user_status, + users.rbac_roles AS user_rbac_roles, + users.login_type AS user_login_type, + users.avatar_url AS user_avatar_url, + users.deleted AS user_deleted, + users.last_seen_at AS user_last_seen_at, + users.quiet_hours_schedule AS user_quiet_hours_schedule, + users.name AS user_name, + users.github_com_user_id AS user_github_com_user_id, + users.is_system AS user_is_system, + users.is_service_account as user_is_service_account, + groups.organization_id, + groups.name AS group_name, + all_members.group_id + FROM ((all_members + JOIN users ON ((users.id = all_members.user_id))) + JOIN groups ON ((groups.id = all_members.group_id))) + WHERE (users.deleted = false); diff --git a/coderd/database/models.go b/coderd/database/models.go index d24c13486c..80972cf7d2 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -4394,7 +4394,6 @@ type Group struct { ChatSpendLimitMicros sql.NullInt64 `db:"chat_spend_limit_micros" json:"chat_spend_limit_micros"` } -// Joins group members with user information, organization ID, group name. Includes both regular group members and organization members (as part of the "Everyone" group). type GroupMember struct { UserID uuid.UUID `db:"user_id" json:"user_id"` UserEmail string `db:"user_email" json:"user_email"` @@ -4412,6 +4411,7 @@ type GroupMember struct { UserName string `db:"user_name" json:"user_name"` UserGithubComUserID sql.NullInt64 `db:"user_github_com_user_id" json:"user_github_com_user_id"` UserIsSystem bool `db:"user_is_system" json:"user_is_system"` + UserIsServiceAccount bool `db:"user_is_service_account" json:"user_is_service_account"` OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` GroupName string `db:"group_name" json:"group_name"` GroupID uuid.UUID `db:"group_id" json:"group_id"` diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index afd9a676c8..c22068e141 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -7293,7 +7293,7 @@ func (q *sqlQuerier) DeleteGroupMemberFromGroup(ctx context.Context, arg DeleteG } const getGroupMembers = `-- name: GetGroupMembers :many -SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, organization_id, group_name, group_id FROM group_members_expanded +SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, user_is_service_account, organization_id, group_name, group_id FROM group_members_expanded WHERE CASE WHEN $1::bool THEN TRUE ELSE @@ -7327,6 +7327,7 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context, includeSystem bool) ([ &i.UserName, &i.UserGithubComUserID, &i.UserIsSystem, + &i.UserIsServiceAccount, &i.OrganizationID, &i.GroupName, &i.GroupID, @@ -7345,7 +7346,7 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context, includeSystem bool) ([ } const getGroupMembersByGroupID = `-- name: GetGroupMembersByGroupID :many -SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, organization_id, group_name, group_id +SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, user_is_service_account, organization_id, group_name, group_id FROM group_members_expanded WHERE group_id = $1 -- Filter by system type @@ -7387,6 +7388,7 @@ func (q *sqlQuerier) GetGroupMembersByGroupID(ctx context.Context, arg GetGroupM &i.UserName, &i.UserGithubComUserID, &i.UserIsSystem, + &i.UserIsServiceAccount, &i.OrganizationID, &i.GroupName, &i.GroupID, @@ -7406,7 +7408,7 @@ func (q *sqlQuerier) GetGroupMembersByGroupID(ctx context.Context, arg GetGroupM const getGroupMembersByGroupIDPaginated = `-- name: GetGroupMembersByGroupIDPaginated :many SELECT - user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, organization_id, group_name, group_id, COUNT(*) OVER() AS count + user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, user_is_service_account, organization_id, group_name, group_id, COUNT(*) OVER() AS count FROM group_members_expanded WHERE @@ -7544,6 +7546,7 @@ type GetGroupMembersByGroupIDPaginatedRow struct { UserName string `db:"user_name" json:"user_name"` UserGithubComUserID sql.NullInt64 `db:"user_github_com_user_id" json:"user_github_com_user_id"` UserIsSystem bool `db:"user_is_system" json:"user_is_system"` + UserIsServiceAccount bool `db:"user_is_service_account" json:"user_is_service_account"` OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` GroupName string `db:"group_name" json:"group_name"` GroupID uuid.UUID `db:"group_id" json:"group_id"` @@ -7592,6 +7595,7 @@ func (q *sqlQuerier) GetGroupMembersByGroupIDPaginated(ctx context.Context, arg &i.UserName, &i.UserGithubComUserID, &i.UserIsSystem, + &i.UserIsServiceAccount, &i.OrganizationID, &i.GroupName, &i.GroupID, @@ -16634,7 +16638,7 @@ FROM ( -- Select all groups this user is a member of. This will also include -- the "Everyone" group for organizations the user is a member of. - SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, organization_id, group_name, group_id FROM group_members_expanded + SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, user_is_system, user_is_service_account, organization_id, group_name, group_id FROM group_members_expanded WHERE $1 = user_id AND $2 = group_members_expanded.organization_id diff --git a/docs/admin/users/index.md b/docs/admin/users/index.md index 4f6f5049d3..c1c528542b 100644 --- a/docs/admin/users/index.md +++ b/docs/admin/users/index.md @@ -207,6 +207,17 @@ The following filters are supported: RFC3339Nano format. - `login_type` - Represents the login type of the user. Refer to the [LoginType documentation](https://pkg.go.dev/github.com/coder/coder/v2/codersdk#LoginType) for a list of supported values +## Edit a user's profile + +To edit a user's display name or username with the web UI: + +1. Log in as a user admin. +2. Go to **Users** +3. Find the user whose details you would like to edit +4. Select **Edit** from the actions menu +5. Make any desired changes +6. Click **Save** + ## Retrieve your list of Coder users