mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: include organization name when fetching templates (#13751)
* chore: include organization name when fetching templates * chore: rename template_with_user to template_with_names
This commit is contained in:
@@ -515,7 +515,7 @@ func (q *FakeQuerier) getLatestWorkspaceBuildByWorkspaceIDNoLock(_ context.Conte
|
||||
func (q *FakeQuerier) getTemplateByIDNoLock(_ context.Context, id uuid.UUID) (database.Template, error) {
|
||||
for _, template := range q.templates {
|
||||
if template.ID == id {
|
||||
return q.templateWithUserNoLock(template), nil
|
||||
return q.templateWithNameNoLock(template), nil
|
||||
}
|
||||
}
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
@@ -524,12 +524,12 @@ func (q *FakeQuerier) getTemplateByIDNoLock(_ context.Context, id uuid.UUID) (da
|
||||
func (q *FakeQuerier) templatesWithUserNoLock(tpl []database.TemplateTable) []database.Template {
|
||||
cpy := make([]database.Template, 0, len(tpl))
|
||||
for _, t := range tpl {
|
||||
cpy = append(cpy, q.templateWithUserNoLock(t))
|
||||
cpy = append(cpy, q.templateWithNameNoLock(t))
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) templateWithUserNoLock(tpl database.TemplateTable) database.Template {
|
||||
func (q *FakeQuerier) templateWithNameNoLock(tpl database.TemplateTable) database.Template {
|
||||
var user database.User
|
||||
for _, _user := range q.users {
|
||||
if _user.ID == tpl.CreatedBy {
|
||||
@@ -537,13 +537,23 @@ func (q *FakeQuerier) templateWithUserNoLock(tpl database.TemplateTable) databas
|
||||
break
|
||||
}
|
||||
}
|
||||
var withUser database.Template
|
||||
|
||||
var org database.Organization
|
||||
for _, _org := range q.organizations {
|
||||
if _org.ID == tpl.OrganizationID {
|
||||
org = _org
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var withNames database.Template
|
||||
// This is a cheeky way to copy the fields over without explicitly listing them all.
|
||||
d, _ := json.Marshal(tpl)
|
||||
_ = json.Unmarshal(d, &withUser)
|
||||
withUser.CreatedByUsername = user.Username
|
||||
withUser.CreatedByAvatarURL = user.AvatarURL
|
||||
return withUser
|
||||
_ = json.Unmarshal(d, &withNames)
|
||||
withNames.CreatedByUsername = user.Username
|
||||
withNames.CreatedByAvatarURL = user.AvatarURL
|
||||
withNames.OrganizationName = org.Name
|
||||
return withNames
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) templateVersionWithUserNoLock(tpl database.TemplateVersionTable) database.TemplateVersion {
|
||||
@@ -3675,7 +3685,7 @@ func (q *FakeQuerier) GetTemplateByOrganizationAndName(_ context.Context, arg da
|
||||
if template.Deleted != arg.Deleted {
|
||||
continue
|
||||
}
|
||||
return q.templateWithUserNoLock(template), nil
|
||||
return q.templateWithNameNoLock(template), nil
|
||||
}
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
}
|
||||
@@ -9323,7 +9333,7 @@ func (q *FakeQuerier) GetAuthorizedTemplates(ctx context.Context, arg database.G
|
||||
|
||||
var templates []database.Template
|
||||
for _, templateTable := range q.templates {
|
||||
template := q.templateWithUserNoLock(templateTable)
|
||||
template := q.templateWithNameNoLock(templateTable)
|
||||
if prepared != nil && prepared.Authorize(ctx, template.RBACObject()) != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
Generated
+7
-5
@@ -1055,7 +1055,7 @@ COMMENT ON COLUMN templates.autostart_block_days_of_week IS 'A bitmap of days of
|
||||
|
||||
COMMENT ON COLUMN templates.deprecated IS 'If set to a non empty string, the template will no longer be able to be used. The message will be displayed to the user.';
|
||||
|
||||
CREATE VIEW template_with_users AS
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.id,
|
||||
templates.created_at,
|
||||
templates.updated_at,
|
||||
@@ -1085,11 +1085,13 @@ CREATE VIEW template_with_users AS
|
||||
templates.activity_bump,
|
||||
templates.max_port_sharing_level,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||
FROM (templates
|
||||
LEFT JOIN visible_users ON ((templates.created_by = visible_users.id)));
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(organizations.name, ''::text) AS organization_name
|
||||
FROM ((templates
|
||||
LEFT JOIN visible_users ON ((templates.created_by = visible_users.id)))
|
||||
LEFT JOIN organizations ON ((templates.organization_id = organizations.id)));
|
||||
|
||||
COMMENT ON VIEW template_with_users IS 'Joins in the username + avatar url of the created by user.';
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
||||
|
||||
CREATE TABLE user_links (
|
||||
user_id uuid NOT NULL,
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestViewSubsetTemplate(t *testing.T) {
|
||||
tableFields := allFields(table)
|
||||
joinedFields := allFields(joined)
|
||||
if !assert.Subset(t, fieldNames(joinedFields), fieldNames(tableFields), "table is not subset") {
|
||||
t.Log("Some fields were added to the Template Table without updating the 'template_with_users' view.")
|
||||
t.Log("Some fields were added to the Template Table without updating the 'template_with_names' view.")
|
||||
t.Log("See migration 000138_join_users.up.sql to create the view.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
DROP VIEW template_with_names;
|
||||
|
||||
CREATE VIEW
|
||||
template_with_users
|
||||
AS
|
||||
SELECT
|
||||
templates.*,
|
||||
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
|
||||
coalesce(visible_users.username, '') AS created_by_username
|
||||
FROM
|
||||
templates
|
||||
LEFT JOIN
|
||||
visible_users
|
||||
ON
|
||||
templates.created_by = visible_users.id;
|
||||
COMMENT ON VIEW template_with_users IS 'Joins in the username + avatar url of the created by user.';
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Update the template_with_users view by recreating it.
|
||||
DROP VIEW template_with_users;
|
||||
|
||||
-- Renaming template_with_users -> template_with_names
|
||||
CREATE VIEW
|
||||
template_with_names
|
||||
AS
|
||||
SELECT
|
||||
templates.*,
|
||||
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
|
||||
coalesce(visible_users.username, '') AS created_by_username,
|
||||
coalesce(organizations.name, '') AS organization_name
|
||||
FROM
|
||||
templates
|
||||
LEFT JOIN
|
||||
visible_users
|
||||
ON
|
||||
templates.created_by = visible_users.id
|
||||
LEFT JOIN
|
||||
organizations
|
||||
ON templates.organization_id = organizations.id
|
||||
;
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
||||
@@ -116,6 +116,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2243,7 +2243,7 @@ type TailnetTunnel struct {
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
// Joins in the username + avatar url of the created by user.
|
||||
// Joins in the display name information such as username, avatar, and organization name.
|
||||
type Template struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
@@ -2275,6 +2275,7 @@ type Template struct {
|
||||
MaxPortSharingLevel AppSharingLevel `db:"max_port_sharing_level" json:"max_port_sharing_level"`
|
||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||
OrganizationName string `db:"organization_name" json:"organization_name"`
|
||||
}
|
||||
|
||||
type TemplateTable struct {
|
||||
|
||||
@@ -7178,9 +7178,9 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg GetTem
|
||||
|
||||
const getTemplateByID = `-- name: GetTemplateByID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name
|
||||
FROM
|
||||
template_with_users
|
||||
template_with_names
|
||||
WHERE
|
||||
id = $1
|
||||
LIMIT
|
||||
@@ -7221,15 +7221,16 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name
|
||||
FROM
|
||||
template_with_users AS templates
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
organization_id = $1
|
||||
AND deleted = $2
|
||||
@@ -7278,12 +7279,13 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTemplates = `-- name: GetTemplates :many
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username FROM template_with_users AS templates
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name FROM template_with_names AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
`
|
||||
|
||||
@@ -7327,6 +7329,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -7343,9 +7346,9 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
|
||||
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name
|
||||
FROM
|
||||
template_with_users AS templates
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
-- Optionally include deleted templates
|
||||
templates.deleted = $1
|
||||
@@ -7437,6 +7440,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
template_with_users
|
||||
template_with_names
|
||||
WHERE
|
||||
id = $1
|
||||
LIMIT
|
||||
@@ -12,7 +12,7 @@ LIMIT
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
template_with_users AS templates
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
-- Optionally include deleted templates
|
||||
templates.deleted = @deleted
|
||||
@@ -54,7 +54,7 @@ ORDER BY (name, id) ASC
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
template_with_users AS templates
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
organization_id = @organization_id
|
||||
AND deleted = @deleted
|
||||
@@ -63,7 +63,7 @@ LIMIT
|
||||
1;
|
||||
|
||||
-- name: GetTemplates :many
|
||||
SELECT * FROM template_with_users AS templates
|
||||
SELECT * FROM template_with_names AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
;
|
||||
|
||||
|
||||
@@ -55,10 +55,10 @@ sql:
|
||||
- column: "templates.group_acl"
|
||||
go_type:
|
||||
type: "TemplateACL"
|
||||
- column: "template_with_users.user_acl"
|
||||
- column: "template_with_names.user_acl"
|
||||
go_type:
|
||||
type: "TemplateACL"
|
||||
- column: "template_with_users.group_acl"
|
||||
- column: "template_with_names.group_acl"
|
||||
go_type:
|
||||
type: "TemplateACL"
|
||||
- column: "template_usage_stats.app_usage_mins"
|
||||
@@ -72,7 +72,7 @@ sql:
|
||||
type: "[]byte"
|
||||
rename:
|
||||
template: TemplateTable
|
||||
template_with_user: Template
|
||||
template_with_name: Template
|
||||
workspace_build: WorkspaceBuildTable
|
||||
workspace_build_with_user: WorkspaceBuild
|
||||
template_version: TemplateVersionTable
|
||||
|
||||
Reference in New Issue
Block a user