mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
chore: add template_with_user
view to include user contextual data (#8568)
* chore: Refactor template sql queries to use new view * TemplateWithUser -> Template * Add unit test to enforce good view
This commit is contained in:
@ -1808,9 +1808,12 @@ func (q *querier) InsertReplica(ctx context.Context, arg database.InsertReplicaP
|
||||
return q.db.InsertReplica(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertTemplate(ctx context.Context, arg database.InsertTemplateParams) (database.Template, error) {
|
||||
func (q *querier) InsertTemplate(ctx context.Context, arg database.InsertTemplateParams) error {
|
||||
obj := rbac.ResourceTemplate.InOrg(arg.OrganizationID)
|
||||
return insert(q.log, q.auth, obj, q.db.InsertTemplate)(ctx, arg)
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.InsertTemplate(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) {
|
||||
@ -2134,13 +2137,13 @@ func (q *querier) UpdateReplica(ctx context.Context, arg database.UpdateReplicaP
|
||||
return q.db.UpdateReplica(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateACLByID(ctx context.Context, arg database.UpdateTemplateACLByIDParams) (database.Template, error) {
|
||||
// UpdateTemplateACL uses the ActionCreate action. Only users that can create the template
|
||||
// may update the ACL.
|
||||
func (q *querier) UpdateTemplateACLByID(ctx context.Context, arg database.UpdateTemplateACLByIDParams) error {
|
||||
fetch := func(ctx context.Context, arg database.UpdateTemplateACLByIDParams) (database.Template, error) {
|
||||
return q.db.GetTemplateByID(ctx, arg.ID)
|
||||
}
|
||||
return fetchAndQuery(q.log, q.auth, rbac.ActionCreate, fetch, q.db.UpdateTemplateACLByID)(ctx, arg)
|
||||
// UpdateTemplateACL uses the ActionCreate action. Only users that can create the template
|
||||
// may update the ACL.
|
||||
return fetchAndExec(q.log, q.auth, rbac.ActionCreate, fetch, q.db.UpdateTemplateACLByID)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateActiveVersionByID(ctx context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error {
|
||||
@ -2155,18 +2158,18 @@ func (q *querier) UpdateTemplateDeletedByID(ctx context.Context, arg database.Up
|
||||
return q.SoftDeleteTemplateByID(ctx, arg.ID)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateMetaByID(ctx context.Context, arg database.UpdateTemplateMetaByIDParams) (database.Template, error) {
|
||||
func (q *querier) UpdateTemplateMetaByID(ctx context.Context, arg database.UpdateTemplateMetaByIDParams) error {
|
||||
fetch := func(ctx context.Context, arg database.UpdateTemplateMetaByIDParams) (database.Template, error) {
|
||||
return q.db.GetTemplateByID(ctx, arg.ID)
|
||||
}
|
||||
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateTemplateMetaByID)(ctx, arg)
|
||||
return update(q.log, q.auth, fetch, q.db.UpdateTemplateMetaByID)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateScheduleByID(ctx context.Context, arg database.UpdateTemplateScheduleByIDParams) (database.Template, error) {
|
||||
func (q *querier) UpdateTemplateScheduleByID(ctx context.Context, arg database.UpdateTemplateScheduleByIDParams) error {
|
||||
fetch := func(ctx context.Context, arg database.UpdateTemplateScheduleByIDParams) (database.Template, error) {
|
||||
return q.db.GetTemplateByID(ctx, arg.ID)
|
||||
}
|
||||
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateTemplateScheduleByID)(ctx, arg)
|
||||
return update(q.log, q.auth, fetch, q.db.UpdateTemplateScheduleByID)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) {
|
||||
|
@ -772,7 +772,7 @@ func (s *MethodTestSuite) TestTemplate() {
|
||||
t1 := dbgen.Template(s.T(), db, database.Template{})
|
||||
check.Args(database.UpdateTemplateACLByIDParams{
|
||||
ID: t1.ID,
|
||||
}).Asserts(t1, rbac.ActionCreate).Returns(t1)
|
||||
}).Asserts(t1, rbac.ActionCreate)
|
||||
}))
|
||||
s.Run("UpdateTemplateActiveVersionByID", s.Subtest(func(db database.Store, check *expects) {
|
||||
t1 := dbgen.Template(s.T(), db, database.Template{
|
||||
|
@ -58,7 +58,7 @@ func New() database.Store {
|
||||
workspaceResourceMetadata: make([]database.WorkspaceResourceMetadatum, 0),
|
||||
provisionerJobs: make([]database.ProvisionerJob, 0),
|
||||
templateVersions: make([]database.TemplateVersion, 0),
|
||||
templates: make([]database.Template, 0),
|
||||
templates: make([]database.TemplateTable, 0),
|
||||
workspaceAgentStats: make([]database.WorkspaceAgentStat, 0),
|
||||
workspaceAgentLogs: make([]database.WorkspaceAgentStartupLog, 0),
|
||||
workspaceBuilds: make([]database.WorkspaceBuild, 0),
|
||||
@ -130,7 +130,7 @@ type data struct {
|
||||
templateVersions []database.TemplateVersion
|
||||
templateVersionParameters []database.TemplateVersionParameter
|
||||
templateVersionVariables []database.TemplateVersionVariable
|
||||
templates []database.Template
|
||||
templates []database.TemplateTable
|
||||
workspaceAgents []database.WorkspaceAgent
|
||||
workspaceAgentMetadata []database.WorkspaceAgentMetadatum
|
||||
workspaceAgentLogs []database.WorkspaceAgentStartupLog
|
||||
@ -446,12 +446,37 @@ 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 template.DeepCopy(), nil
|
||||
return q.templateWithUserNoLock(template), nil
|
||||
}
|
||||
}
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) templateWithUserNoLock(tpl database.TemplateTable) database.Template {
|
||||
var user database.User
|
||||
for _, _user := range q.users {
|
||||
if _user.ID == tpl.CreatedBy {
|
||||
user = _user
|
||||
break
|
||||
}
|
||||
}
|
||||
var withUser 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.String
|
||||
return withUser
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) getTemplateVersionByIDNoLock(_ context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) {
|
||||
for _, templateVersion := range q.templateVersions {
|
||||
if templateVersion.ID != templateVersionID {
|
||||
@ -1869,7 +1894,7 @@ func (q *FakeQuerier) GetTemplateByOrganizationAndName(_ context.Context, arg da
|
||||
if template.Deleted != arg.Deleted {
|
||||
continue
|
||||
}
|
||||
return template.DeepCopy(), nil
|
||||
return q.templateWithUserNoLock(template), nil
|
||||
}
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
}
|
||||
@ -2092,17 +2117,14 @@ func (q *FakeQuerier) GetTemplates(_ context.Context) ([]database.Template, erro
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
templates := slices.Clone(q.templates)
|
||||
for i := range templates {
|
||||
templates[i] = templates[i].DeepCopy()
|
||||
}
|
||||
slices.SortFunc(templates, func(i, j database.Template) bool {
|
||||
slices.SortFunc(templates, func(i, j database.TemplateTable) bool {
|
||||
if i.Name != j.Name {
|
||||
return i.Name < j.Name
|
||||
}
|
||||
return i.ID.String() < j.ID.String()
|
||||
})
|
||||
|
||||
return templates, nil
|
||||
return q.templatesWithUserNoLock(templates), nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetTemplatesWithFilter(ctx context.Context, arg database.GetTemplatesWithFilterParams) ([]database.Template, error) {
|
||||
@ -3436,16 +3458,16 @@ func (q *FakeQuerier) InsertReplica(_ context.Context, arg database.InsertReplic
|
||||
return replica, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTemplateParams) (database.Template, error) {
|
||||
func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTemplateParams) error {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.Template{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
//nolint:gosimple
|
||||
template := database.Template{
|
||||
template := database.TemplateTable{
|
||||
ID: arg.ID,
|
||||
CreatedAt: arg.CreatedAt,
|
||||
UpdatedAt: arg.UpdatedAt,
|
||||
@ -3464,7 +3486,7 @@ func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl
|
||||
AllowUserAutostop: true,
|
||||
}
|
||||
q.templates = append(q.templates, template)
|
||||
return template.DeepCopy(), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) {
|
||||
@ -4172,9 +4194,9 @@ func (q *FakeQuerier) UpdateReplica(_ context.Context, arg database.UpdateReplic
|
||||
return database.Replica{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateTemplateACLByID(_ context.Context, arg database.UpdateTemplateACLByIDParams) (database.Template, error) {
|
||||
func (q *FakeQuerier) UpdateTemplateACLByID(_ context.Context, arg database.UpdateTemplateACLByIDParams) error {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.Template{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
@ -4186,11 +4208,11 @@ func (q *FakeQuerier) UpdateTemplateACLByID(_ context.Context, arg database.Upda
|
||||
template.UserACL = arg.UserACL
|
||||
|
||||
q.templates[i] = template
|
||||
return template.DeepCopy(), nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateTemplateActiveVersionByID(_ context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error {
|
||||
@ -4233,9 +4255,9 @@ func (q *FakeQuerier) UpdateTemplateDeletedByID(_ context.Context, arg database.
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.UpdateTemplateMetaByIDParams) (database.Template, error) {
|
||||
func (q *FakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.UpdateTemplateMetaByIDParams) error {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.Template{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
@ -4251,15 +4273,15 @@ func (q *FakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd
|
||||
tpl.Description = arg.Description
|
||||
tpl.Icon = arg.Icon
|
||||
q.templates[idx] = tpl
|
||||
return tpl.DeepCopy(), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database.UpdateTemplateScheduleByIDParams) (database.Template, error) {
|
||||
func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database.UpdateTemplateScheduleByIDParams) error {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.Template{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
@ -4278,10 +4300,10 @@ func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database
|
||||
tpl.InactivityTTL = arg.InactivityTTL
|
||||
tpl.LockedTTL = arg.LockedTTL
|
||||
q.templates[idx] = tpl
|
||||
return tpl.DeepCopy(), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return database.Template{}, sql.ErrNoRows
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) {
|
||||
@ -4984,7 +5006,8 @@ func (q *FakeQuerier) GetAuthorizedTemplates(ctx context.Context, arg database.G
|
||||
}
|
||||
|
||||
var templates []database.Template
|
||||
for _, template := range q.templates {
|
||||
for _, templateTable := range q.templates {
|
||||
template := q.templateWithUserNoLock(templateTable)
|
||||
if prepared != nil && prepared.Authorize(ctx, template.RBACObject()) != nil {
|
||||
continue
|
||||
}
|
||||
@ -5012,7 +5035,7 @@ func (q *FakeQuerier) GetAuthorizedTemplates(ctx context.Context, arg database.G
|
||||
continue
|
||||
}
|
||||
}
|
||||
templates = append(templates, template.DeepCopy())
|
||||
templates = append(templates, template)
|
||||
}
|
||||
if len(templates) > 0 {
|
||||
slices.SortFunc(templates, func(i, j database.Template) bool {
|
||||
@ -5031,7 +5054,7 @@ func (q *FakeQuerier) GetTemplateGroupRoles(_ context.Context, id uuid.UUID) ([]
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
var template database.Template
|
||||
var template database.TemplateTable
|
||||
for _, t := range q.templates {
|
||||
if t.ID == id {
|
||||
template = t
|
||||
@ -5068,7 +5091,7 @@ func (q *FakeQuerier) GetTemplateUserRoles(_ context.Context, id uuid.UUID) ([]d
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
var template database.Template
|
||||
var template database.TemplateTable
|
||||
for _, t := range q.templates {
|
||||
if t.ID == id {
|
||||
template = t
|
||||
|
@ -62,8 +62,9 @@ func AuditLog(t testing.TB, db database.Store, seed database.AuditLog) database.
|
||||
}
|
||||
|
||||
func Template(t testing.TB, db database.Store, seed database.Template) database.Template {
|
||||
template, err := db.InsertTemplate(genCtx, database.InsertTemplateParams{
|
||||
ID: takeFirst(seed.ID, uuid.New()),
|
||||
id := takeFirst(seed.ID, uuid.New())
|
||||
err := db.InsertTemplate(genCtx, database.InsertTemplateParams{
|
||||
ID: id,
|
||||
CreatedAt: takeFirst(seed.CreatedAt, database.Now()),
|
||||
UpdatedAt: takeFirst(seed.UpdatedAt, database.Now()),
|
||||
OrganizationID: takeFirst(seed.OrganizationID, uuid.New()),
|
||||
@ -79,6 +80,9 @@ func Template(t testing.TB, db database.Store, seed database.Template) database.
|
||||
AllowUserCancelWorkspaceJobs: seed.AllowUserCancelWorkspaceJobs,
|
||||
})
|
||||
require.NoError(t, err, "insert template")
|
||||
|
||||
template, err := db.GetTemplateByID(context.Background(), id)
|
||||
require.NoError(t, err, "get template")
|
||||
return template
|
||||
}
|
||||
|
||||
|
@ -1103,11 +1103,11 @@ func (m metricsStore) InsertReplica(ctx context.Context, arg database.InsertRepl
|
||||
return replica, err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertTemplate(ctx context.Context, arg database.InsertTemplateParams) (database.Template, error) {
|
||||
func (m metricsStore) InsertTemplate(ctx context.Context, arg database.InsertTemplateParams) error {
|
||||
start := time.Now()
|
||||
template, err := m.s.InsertTemplate(ctx, arg)
|
||||
err := m.s.InsertTemplate(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("InsertTemplate").Observe(time.Since(start).Seconds())
|
||||
return template, err
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) {
|
||||
@ -1306,11 +1306,11 @@ func (m metricsStore) UpdateReplica(ctx context.Context, arg database.UpdateRepl
|
||||
return replica, err
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateTemplateACLByID(ctx context.Context, arg database.UpdateTemplateACLByIDParams) (database.Template, error) {
|
||||
func (m metricsStore) UpdateTemplateACLByID(ctx context.Context, arg database.UpdateTemplateACLByIDParams) error {
|
||||
start := time.Now()
|
||||
template, err := m.s.UpdateTemplateACLByID(ctx, arg)
|
||||
err := m.s.UpdateTemplateACLByID(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpdateTemplateACLByID").Observe(time.Since(start).Seconds())
|
||||
return template, err
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateTemplateActiveVersionByID(ctx context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error {
|
||||
@ -1327,18 +1327,18 @@ func (m metricsStore) UpdateTemplateDeletedByID(ctx context.Context, arg databas
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateTemplateMetaByID(ctx context.Context, arg database.UpdateTemplateMetaByIDParams) (database.Template, error) {
|
||||
func (m metricsStore) UpdateTemplateMetaByID(ctx context.Context, arg database.UpdateTemplateMetaByIDParams) error {
|
||||
start := time.Now()
|
||||
template, err := m.s.UpdateTemplateMetaByID(ctx, arg)
|
||||
err := m.s.UpdateTemplateMetaByID(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpdateTemplateMetaByID").Observe(time.Since(start).Seconds())
|
||||
return template, err
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateTemplateScheduleByID(ctx context.Context, arg database.UpdateTemplateScheduleByIDParams) (database.Template, error) {
|
||||
func (m metricsStore) UpdateTemplateScheduleByID(ctx context.Context, arg database.UpdateTemplateScheduleByIDParams) error {
|
||||
start := time.Now()
|
||||
template, err := m.s.UpdateTemplateScheduleByID(ctx, arg)
|
||||
err := m.s.UpdateTemplateScheduleByID(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpdateTemplateScheduleByID").Observe(time.Since(start).Seconds())
|
||||
return template, err
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) {
|
||||
|
@ -2318,12 +2318,11 @@ func (mr *MockStoreMockRecorder) InsertReplica(arg0, arg1 interface{}) *gomock.C
|
||||
}
|
||||
|
||||
// InsertTemplate mocks base method.
|
||||
func (m *MockStore) InsertTemplate(arg0 context.Context, arg1 database.InsertTemplateParams) (database.Template, error) {
|
||||
func (m *MockStore) InsertTemplate(arg0 context.Context, arg1 database.InsertTemplateParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InsertTemplate", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.Template)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InsertTemplate indicates an expected call of InsertTemplate.
|
||||
@ -2761,12 +2760,11 @@ func (mr *MockStoreMockRecorder) UpdateReplica(arg0, arg1 interface{}) *gomock.C
|
||||
}
|
||||
|
||||
// UpdateTemplateACLByID mocks base method.
|
||||
func (m *MockStore) UpdateTemplateACLByID(arg0 context.Context, arg1 database.UpdateTemplateACLByIDParams) (database.Template, error) {
|
||||
func (m *MockStore) UpdateTemplateACLByID(arg0 context.Context, arg1 database.UpdateTemplateACLByIDParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateTemplateACLByID", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.Template)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateTemplateACLByID indicates an expected call of UpdateTemplateACLByID.
|
||||
@ -2804,12 +2802,11 @@ func (mr *MockStoreMockRecorder) UpdateTemplateDeletedByID(arg0, arg1 interface{
|
||||
}
|
||||
|
||||
// UpdateTemplateMetaByID mocks base method.
|
||||
func (m *MockStore) UpdateTemplateMetaByID(arg0 context.Context, arg1 database.UpdateTemplateMetaByIDParams) (database.Template, error) {
|
||||
func (m *MockStore) UpdateTemplateMetaByID(arg0 context.Context, arg1 database.UpdateTemplateMetaByIDParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateTemplateMetaByID", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.Template)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateTemplateMetaByID indicates an expected call of UpdateTemplateMetaByID.
|
||||
@ -2819,12 +2816,11 @@ func (mr *MockStoreMockRecorder) UpdateTemplateMetaByID(arg0, arg1 interface{})
|
||||
}
|
||||
|
||||
// UpdateTemplateScheduleByID mocks base method.
|
||||
func (m *MockStore) UpdateTemplateScheduleByID(arg0 context.Context, arg1 database.UpdateTemplateScheduleByIDParams) (database.Template, error) {
|
||||
func (m *MockStore) UpdateTemplateScheduleByID(arg0 context.Context, arg1 database.UpdateTemplateScheduleByIDParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateTemplateScheduleByID", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.Template)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateTemplateScheduleByID indicates an expected call of UpdateTemplateScheduleByID.
|
||||
|
56
coderd/database/dump.sql
generated
56
coderd/database/dump.sql
generated
@ -579,15 +579,6 @@ COMMENT ON COLUMN templates.allow_user_autostart IS 'Allow users to specify an a
|
||||
|
||||
COMMENT ON COLUMN templates.allow_user_autostop IS 'Allow users to specify custom autostop values for workspaces (enterprise).';
|
||||
|
||||
CREATE TABLE user_links (
|
||||
user_id uuid NOT NULL,
|
||||
login_type login_type NOT NULL,
|
||||
linked_id text DEFAULT ''::text NOT NULL,
|
||||
oauth_access_token text DEFAULT ''::text NOT NULL,
|
||||
oauth_refresh_token text DEFAULT ''::text NOT NULL,
|
||||
oauth_expiry timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id uuid NOT NULL,
|
||||
email text NOT NULL,
|
||||
@ -603,6 +594,53 @@ CREATE TABLE users (
|
||||
last_seen_at timestamp without time zone DEFAULT '0001-01-01 00:00:00'::timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE VIEW visible_users AS
|
||||
SELECT users.id,
|
||||
users.username,
|
||||
users.avatar_url
|
||||
FROM users;
|
||||
|
||||
COMMENT ON VIEW visible_users IS 'Visible fields of users are allowed to be joined with other tables for including context of other resources.';
|
||||
|
||||
CREATE VIEW template_with_users AS
|
||||
SELECT templates.id,
|
||||
templates.created_at,
|
||||
templates.updated_at,
|
||||
templates.organization_id,
|
||||
templates.deleted,
|
||||
templates.name,
|
||||
templates.provisioner,
|
||||
templates.active_version_id,
|
||||
templates.description,
|
||||
templates.default_ttl,
|
||||
templates.created_by,
|
||||
templates.icon,
|
||||
templates.user_acl,
|
||||
templates.group_acl,
|
||||
templates.display_name,
|
||||
templates.allow_user_cancel_workspace_jobs,
|
||||
templates.max_ttl,
|
||||
templates.allow_user_autostart,
|
||||
templates.allow_user_autostop,
|
||||
templates.failure_ttl,
|
||||
templates.inactivity_ttl,
|
||||
templates.locked_ttl,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||
FROM (public.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.';
|
||||
|
||||
CREATE TABLE user_links (
|
||||
user_id uuid NOT NULL,
|
||||
login_type login_type NOT NULL,
|
||||
linked_id text DEFAULT ''::text NOT NULL,
|
||||
oauth_access_token text DEFAULT ''::text NOT NULL,
|
||||
oauth_refresh_token text DEFAULT ''::text NOT NULL,
|
||||
oauth_expiry timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNLOGGED TABLE workspace_agent_metadata (
|
||||
workspace_agent_id uuid NOT NULL,
|
||||
display_name character varying(127) NOT NULL,
|
||||
|
@ -57,4 +57,6 @@ SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
|
||||
go run golang.org/x/tools/cmd/goimports@latest -w queries.sql.go
|
||||
|
||||
go run ../../scripts/dbgen/main.go
|
||||
# This will error if a view is broken.
|
||||
go test -run=TestViewSubset
|
||||
)
|
||||
|
6
coderd/database/migrations/000138_join_users.down.sql
Normal file
6
coderd/database/migrations/000138_join_users.down.sql
Normal file
@ -0,0 +1,6 @@
|
||||
BEGIN;
|
||||
|
||||
DROP VIEW template_with_users;
|
||||
DROP VIEW visible_users;
|
||||
|
||||
COMMIT;
|
30
coderd/database/migrations/000138_join_users.up.sql
Normal file
30
coderd/database/migrations/000138_join_users.up.sql
Normal file
@ -0,0 +1,30 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE VIEW
|
||||
visible_users
|
||||
AS
|
||||
SELECT
|
||||
id, username, avatar_url
|
||||
FROM
|
||||
users;
|
||||
|
||||
COMMENT ON VIEW visible_users IS 'Visible fields of users are allowed to be joined with other tables for including context of other resources.';
|
||||
|
||||
-- If you need to update this view, put 'DROP VIEW template_with_users;' before this.
|
||||
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.';
|
||||
|
||||
COMMIT;
|
@ -54,7 +54,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
pq.Array(arg.IDs),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("query context: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Template
|
||||
@ -83,16 +83,18 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
return nil, xerrors.Errorf("scan: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, xerrors.Errorf("close: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, xerrors.Errorf("rows err: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
@ -1567,7 +1567,35 @@ type TailnetCoordinator struct {
|
||||
HeartbeatAt time.Time `db:"heartbeat_at" json:"heartbeat_at"`
|
||||
}
|
||||
|
||||
// Joins in the username + avatar url of the created by user.
|
||||
type Template struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
|
||||
Deleted bool `db:"deleted" json:"deleted"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Provisioner ProvisionerType `db:"provisioner" json:"provisioner"`
|
||||
ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"`
|
||||
Description string `db:"description" json:"description"`
|
||||
DefaultTTL int64 `db:"default_ttl" json:"default_ttl"`
|
||||
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
UserACL TemplateACL `db:"user_acl" json:"user_acl"`
|
||||
GroupACL TemplateACL `db:"group_acl" json:"group_acl"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
|
||||
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
|
||||
AllowUserAutostart bool `db:"allow_user_autostart" json:"allow_user_autostart"`
|
||||
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
|
||||
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
|
||||
InactivityTTL int64 `db:"inactivity_ttl" json:"inactivity_ttl"`
|
||||
LockedTTL int64 `db:"locked_ttl" json:"locked_ttl"`
|
||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||
}
|
||||
|
||||
type TemplateTable struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
@ -1691,6 +1719,13 @@ type UserLink struct {
|
||||
OAuthExpiry time.Time `db:"oauth_expiry" json:"oauth_expiry"`
|
||||
}
|
||||
|
||||
// Visible fields of users are allowed to be joined with other tables for including context of other resources.
|
||||
type VisibleUser struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
Username string `db:"username" json:"username"`
|
||||
AvatarURL sql.NullString `db:"avatar_url" json:"avatar_url"`
|
||||
}
|
||||
|
||||
type Workspace struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
|
46
coderd/database/models_test.go
Normal file
46
coderd/database/models_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package database_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
)
|
||||
|
||||
// TestViewSubsetTemplate ensures TemplateTable is a subset of Template
|
||||
func TestViewSubsetTemplate(t *testing.T) {
|
||||
t.Parallel()
|
||||
table := reflect.TypeOf(database.TemplateTable{})
|
||||
joined := reflect.TypeOf(database.Template{})
|
||||
|
||||
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("See migration 000138_join_users_up.sql to create the view.")
|
||||
}
|
||||
}
|
||||
|
||||
func fieldNames(fields []reflect.StructField) []string {
|
||||
names := make([]string, len(fields))
|
||||
for i, field := range fields {
|
||||
names[i] = field.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func allFields(rt reflect.Type) []reflect.StructField {
|
||||
fields := make([]reflect.StructField, 0, rt.NumField())
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
field := rt.Field(i)
|
||||
if field.Anonymous && field.Type.Kind() == reflect.Struct {
|
||||
// Recurse into anonymous struct fields.
|
||||
fields = append(fields, allFields(field.Type)...)
|
||||
continue
|
||||
}
|
||||
fields = append(fields, rt.Field(i))
|
||||
}
|
||||
return fields
|
||||
}
|
@ -191,7 +191,7 @@ type sqlcQuerier interface {
|
||||
InsertProvisionerJob(ctx context.Context, arg InsertProvisionerJobParams) (ProvisionerJob, error)
|
||||
InsertProvisionerJobLogs(ctx context.Context, arg InsertProvisionerJobLogsParams) ([]ProvisionerJobLog, error)
|
||||
InsertReplica(ctx context.Context, arg InsertReplicaParams) (Replica, error)
|
||||
InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error)
|
||||
InsertTemplate(ctx context.Context, arg InsertTemplateParams) error
|
||||
InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) (TemplateVersion, error)
|
||||
InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error)
|
||||
InsertTemplateVersionVariable(ctx context.Context, arg InsertTemplateVersionVariableParams) (TemplateVersionVariable, error)
|
||||
@ -225,11 +225,11 @@ type sqlcQuerier interface {
|
||||
UpdateProvisionerJobWithCancelByID(ctx context.Context, arg UpdateProvisionerJobWithCancelByIDParams) error
|
||||
UpdateProvisionerJobWithCompleteByID(ctx context.Context, arg UpdateProvisionerJobWithCompleteByIDParams) error
|
||||
UpdateReplica(ctx context.Context, arg UpdateReplicaParams) (Replica, error)
|
||||
UpdateTemplateACLByID(ctx context.Context, arg UpdateTemplateACLByIDParams) (Template, error)
|
||||
UpdateTemplateACLByID(ctx context.Context, arg UpdateTemplateACLByIDParams) error
|
||||
UpdateTemplateActiveVersionByID(ctx context.Context, arg UpdateTemplateActiveVersionByIDParams) error
|
||||
UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTemplateDeletedByIDParams) error
|
||||
UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) (Template, error)
|
||||
UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) (Template, error)
|
||||
UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error
|
||||
UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) error
|
||||
UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) (TemplateVersion, error)
|
||||
UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error
|
||||
UpdateTemplateVersionGitAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionGitAuthProvidersByJobIDParams) error
|
||||
|
@ -3637,9 +3637,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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
templates
|
||||
template_with_users
|
||||
WHERE
|
||||
id = $1
|
||||
LIMIT
|
||||
@ -3672,15 +3672,17 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
templates
|
||||
template_with_users AS templates
|
||||
WHERE
|
||||
organization_id = $1
|
||||
AND deleted = $2
|
||||
@ -3721,12 +3723,14 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl FROM 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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl, created_by_avatar_url, created_by_username FROM template_with_users AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
`
|
||||
|
||||
@ -3762,6 +3766,8 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -3778,9 +3784,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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
templates
|
||||
template_with_users AS templates
|
||||
WHERE
|
||||
-- Optionally include deleted templates
|
||||
templates.deleted = $1
|
||||
@ -3851,6 +3857,8 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -3865,7 +3873,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const insertTemplate = `-- name: InsertTemplate :one
|
||||
const insertTemplate = `-- name: InsertTemplate :exec
|
||||
INSERT INTO
|
||||
templates (
|
||||
id,
|
||||
@ -3884,7 +3892,7 @@ INSERT INTO
|
||||
allow_user_cancel_workspace_jobs
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING 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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
|
||||
`
|
||||
|
||||
type InsertTemplateParams struct {
|
||||
@ -3904,8 +3912,8 @@ type InsertTemplateParams struct {
|
||||
AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error) {
|
||||
row := q.db.QueryRowContext(ctx, insertTemplate,
|
||||
func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParams) error {
|
||||
_, err := q.db.ExecContext(ctx, insertTemplate,
|
||||
arg.ID,
|
||||
arg.CreatedAt,
|
||||
arg.UpdatedAt,
|
||||
@ -3921,35 +3929,10 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam
|
||||
arg.DisplayName,
|
||||
arg.AllowUserCancelWorkspaceJobs,
|
||||
)
|
||||
var i Template
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.OrganizationID,
|
||||
&i.Deleted,
|
||||
&i.Name,
|
||||
&i.Provisioner,
|
||||
&i.ActiveVersionID,
|
||||
&i.Description,
|
||||
&i.DefaultTTL,
|
||||
&i.CreatedBy,
|
||||
&i.Icon,
|
||||
&i.UserACL,
|
||||
&i.GroupACL,
|
||||
&i.DisplayName,
|
||||
&i.AllowUserCancelWorkspaceJobs,
|
||||
&i.MaxTTL,
|
||||
&i.AllowUserAutostart,
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
||||
const updateTemplateACLByID = `-- name: UpdateTemplateACLByID :one
|
||||
const updateTemplateACLByID = `-- name: UpdateTemplateACLByID :exec
|
||||
UPDATE
|
||||
templates
|
||||
SET
|
||||
@ -3957,8 +3940,6 @@ SET
|
||||
user_acl = $2
|
||||
WHERE
|
||||
id = $3
|
||||
RETURNING
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type UpdateTemplateACLByIDParams struct {
|
||||
@ -3967,34 +3948,9 @@ type UpdateTemplateACLByIDParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateTemplateACLByID(ctx context.Context, arg UpdateTemplateACLByIDParams) (Template, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTemplateACLByID, arg.GroupACL, arg.UserACL, arg.ID)
|
||||
var i Template
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.OrganizationID,
|
||||
&i.Deleted,
|
||||
&i.Name,
|
||||
&i.Provisioner,
|
||||
&i.ActiveVersionID,
|
||||
&i.Description,
|
||||
&i.DefaultTTL,
|
||||
&i.CreatedBy,
|
||||
&i.Icon,
|
||||
&i.UserACL,
|
||||
&i.GroupACL,
|
||||
&i.DisplayName,
|
||||
&i.AllowUserCancelWorkspaceJobs,
|
||||
&i.MaxTTL,
|
||||
&i.AllowUserAutostart,
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
func (q *sqlQuerier) UpdateTemplateACLByID(ctx context.Context, arg UpdateTemplateACLByIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateTemplateACLByID, arg.GroupACL, arg.UserACL, arg.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateTemplateActiveVersionByID = `-- name: UpdateTemplateActiveVersionByID :exec
|
||||
@ -4039,7 +3995,7 @@ func (q *sqlQuerier) UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTe
|
||||
return err
|
||||
}
|
||||
|
||||
const updateTemplateMetaByID = `-- name: UpdateTemplateMetaByID :one
|
||||
const updateTemplateMetaByID = `-- name: UpdateTemplateMetaByID :exec
|
||||
UPDATE
|
||||
templates
|
||||
SET
|
||||
@ -4051,8 +4007,6 @@ SET
|
||||
allow_user_cancel_workspace_jobs = $7
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type UpdateTemplateMetaByIDParams struct {
|
||||
@ -4065,8 +4019,8 @@ type UpdateTemplateMetaByIDParams struct {
|
||||
AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) (Template, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTemplateMetaByID,
|
||||
func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateTemplateMetaByID,
|
||||
arg.ID,
|
||||
arg.UpdatedAt,
|
||||
arg.Description,
|
||||
@ -4075,35 +4029,10 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
|
||||
arg.DisplayName,
|
||||
arg.AllowUserCancelWorkspaceJobs,
|
||||
)
|
||||
var i Template
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.OrganizationID,
|
||||
&i.Deleted,
|
||||
&i.Name,
|
||||
&i.Provisioner,
|
||||
&i.ActiveVersionID,
|
||||
&i.Description,
|
||||
&i.DefaultTTL,
|
||||
&i.CreatedBy,
|
||||
&i.Icon,
|
||||
&i.UserACL,
|
||||
&i.GroupACL,
|
||||
&i.DisplayName,
|
||||
&i.AllowUserCancelWorkspaceJobs,
|
||||
&i.MaxTTL,
|
||||
&i.AllowUserAutostart,
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
||||
const updateTemplateScheduleByID = `-- name: UpdateTemplateScheduleByID :one
|
||||
const updateTemplateScheduleByID = `-- name: UpdateTemplateScheduleByID :exec
|
||||
UPDATE
|
||||
templates
|
||||
SET
|
||||
@ -4117,8 +4046,6 @@ SET
|
||||
locked_ttl = $9
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
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, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type UpdateTemplateScheduleByIDParams struct {
|
||||
@ -4133,8 +4060,8 @@ type UpdateTemplateScheduleByIDParams struct {
|
||||
LockedTTL int64 `db:"locked_ttl" json:"locked_ttl"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) (Template, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTemplateScheduleByID,
|
||||
func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateTemplateScheduleByID,
|
||||
arg.ID,
|
||||
arg.UpdatedAt,
|
||||
arg.AllowUserAutostart,
|
||||
@ -4145,32 +4072,7 @@ func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateT
|
||||
arg.InactivityTTL,
|
||||
arg.LockedTTL,
|
||||
)
|
||||
var i Template
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.OrganizationID,
|
||||
&i.Deleted,
|
||||
&i.Name,
|
||||
&i.Provisioner,
|
||||
&i.ActiveVersionID,
|
||||
&i.Description,
|
||||
&i.DefaultTTL,
|
||||
&i.CreatedBy,
|
||||
&i.Icon,
|
||||
&i.UserACL,
|
||||
&i.GroupACL,
|
||||
&i.DisplayName,
|
||||
&i.AllowUserCancelWorkspaceJobs,
|
||||
&i.MaxTTL,
|
||||
&i.AllowUserAutostart,
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
||||
const getTemplateVersionParameters = `-- name: GetTemplateVersionParameters :many
|
||||
|
@ -2,7 +2,7 @@
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
templates
|
||||
template_with_users
|
||||
WHERE
|
||||
id = $1
|
||||
LIMIT
|
||||
@ -12,7 +12,7 @@ LIMIT
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
templates
|
||||
template_with_users AS templates
|
||||
WHERE
|
||||
-- Optionally include deleted templates
|
||||
templates.deleted = @deleted
|
||||
@ -43,7 +43,7 @@ ORDER BY (name, id) ASC
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
templates
|
||||
template_with_users AS templates
|
||||
WHERE
|
||||
organization_id = @organization_id
|
||||
AND deleted = @deleted
|
||||
@ -52,11 +52,11 @@ LIMIT
|
||||
1;
|
||||
|
||||
-- name: GetTemplates :many
|
||||
SELECT * FROM templates
|
||||
SELECT * FROM template_with_users AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
;
|
||||
|
||||
-- name: InsertTemplate :one
|
||||
-- name: InsertTemplate :exec
|
||||
INSERT INTO
|
||||
templates (
|
||||
id,
|
||||
@ -75,7 +75,7 @@ INSERT INTO
|
||||
allow_user_cancel_workspace_jobs
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING *;
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);
|
||||
|
||||
-- name: UpdateTemplateActiveVersionByID :exec
|
||||
UPDATE
|
||||
@ -95,7 +95,7 @@ SET
|
||||
WHERE
|
||||
id = $1;
|
||||
|
||||
-- name: UpdateTemplateMetaByID :one
|
||||
-- name: UpdateTemplateMetaByID :exec
|
||||
UPDATE
|
||||
templates
|
||||
SET
|
||||
@ -107,10 +107,9 @@ SET
|
||||
allow_user_cancel_workspace_jobs = $7
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
*;
|
||||
;
|
||||
|
||||
-- name: UpdateTemplateScheduleByID :one
|
||||
-- name: UpdateTemplateScheduleByID :exec
|
||||
UPDATE
|
||||
templates
|
||||
SET
|
||||
@ -124,10 +123,9 @@ SET
|
||||
locked_ttl = $9
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
*;
|
||||
;
|
||||
|
||||
-- name: UpdateTemplateACLByID :one
|
||||
-- name: UpdateTemplateACLByID :exec
|
||||
UPDATE
|
||||
templates
|
||||
SET
|
||||
@ -135,8 +133,7 @@ SET
|
||||
user_acl = $2
|
||||
WHERE
|
||||
id = $3
|
||||
RETURNING
|
||||
*;
|
||||
;
|
||||
|
||||
-- name: GetTemplateAverageBuildTime :one
|
||||
WITH build_times AS (
|
||||
|
@ -21,12 +21,24 @@ overrides:
|
||||
- column: "templates.group_acl"
|
||||
go_type:
|
||||
type: "TemplateACL"
|
||||
- column: "template_with_users.user_acl"
|
||||
go_type:
|
||||
type: "TemplateACL"
|
||||
- column: "template_with_users.group_acl"
|
||||
go_type:
|
||||
type: "TemplateACL"
|
||||
- column: "template_with_users.created_by_avatar_url"
|
||||
go_type:
|
||||
type: "string"
|
||||
rename:
|
||||
template: TemplateTable
|
||||
template_with_user: Template
|
||||
api_key: APIKey
|
||||
api_key_scope: APIKeyScope
|
||||
api_key_scope_all: APIKeyScopeAll
|
||||
api_key_scope_application_connect: APIKeyScopeApplicationConnect
|
||||
avatar_url: AvatarURL
|
||||
created_by_avatar_url: CreatedByAvatarURL
|
||||
session_count_vscode: SessionCountVSCode
|
||||
session_count_jetbrains: SessionCountJetBrains
|
||||
session_count_reconnecting_pty: SessionCountReconnectingPTY
|
||||
|
@ -349,11 +349,14 @@ func TestCache_BuildTime(t *testing.T) {
|
||||
|
||||
defer cache.Close()
|
||||
|
||||
template, err := db.InsertTemplate(ctx, database.InsertTemplateParams{
|
||||
ID: uuid.New(),
|
||||
id := uuid.New()
|
||||
err := db.InsertTemplate(ctx, database.InsertTemplateParams{
|
||||
ID: id,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
template, err := db.GetTemplateByID(ctx, id)
|
||||
require.NoError(t, err)
|
||||
|
||||
templateVersion, err := db.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{
|
||||
ID: uuid.New(),
|
||||
|
@ -1025,7 +1025,7 @@ func TestCompleteJob(t *testing.T) {
|
||||
Name: "template",
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
})
|
||||
template, err := srv.Database.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||
err := srv.Database.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||
ID: template.ID,
|
||||
UpdatedAt: database.Now(),
|
||||
AllowUserAutostart: c.templateAllowAutostop,
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
@ -68,17 +70,35 @@ func (*agplTemplateScheduleStore) SetTemplateScheduleOptions(ctx context.Context
|
||||
return tpl, nil
|
||||
}
|
||||
|
||||
return db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||
ID: tpl.ID,
|
||||
UpdatedAt: database.Now(),
|
||||
DefaultTTL: int64(opts.DefaultTTL),
|
||||
// Don't allow changing it, but keep the value in the DB (to avoid
|
||||
// clearing settings if the license has an issue).
|
||||
AllowUserAutostart: tpl.AllowUserAutostart,
|
||||
AllowUserAutostop: tpl.AllowUserAutostop,
|
||||
MaxTTL: tpl.MaxTTL,
|
||||
FailureTTL: tpl.FailureTTL,
|
||||
InactivityTTL: tpl.InactivityTTL,
|
||||
LockedTTL: tpl.LockedTTL,
|
||||
})
|
||||
var template database.Template
|
||||
err := db.InTx(func(db database.Store) error {
|
||||
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||
ID: tpl.ID,
|
||||
UpdatedAt: database.Now(),
|
||||
DefaultTTL: int64(opts.DefaultTTL),
|
||||
// Don't allow changing it, but keep the value in the DB (to avoid
|
||||
// clearing settings if the license has an issue).
|
||||
AllowUserAutostart: tpl.AllowUserAutostart,
|
||||
AllowUserAutostop: tpl.AllowUserAutostop,
|
||||
MaxTTL: tpl.MaxTTL,
|
||||
FailureTTL: tpl.FailureTTL,
|
||||
InactivityTTL: tpl.InactivityTTL,
|
||||
LockedTTL: tpl.LockedTTL,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update template schedule: %w", err)
|
||||
}
|
||||
|
||||
template, err = db.GetTemplateByID(ctx, tpl.ID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("fetch updated template: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return database.Template{}, err
|
||||
}
|
||||
|
||||
return template, err
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package coderd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -40,16 +39,7 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
template := httpmw.TemplateParam(r)
|
||||
|
||||
createdByNameMap, err := getCreatedByNamesByTemplateIDs(ctx, api.Database, []database.Template{template})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching creator name.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(template, createdByNameMap[template.ID.String()]))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(template))
|
||||
}
|
||||
|
||||
// @Summary Delete template by ID
|
||||
@ -290,8 +280,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
err = api.Database.InTx(func(tx database.Store) error {
|
||||
now := database.Now()
|
||||
dbTemplate, err = tx.InsertTemplate(ctx, database.InsertTemplateParams{
|
||||
ID: uuid.New(),
|
||||
id := uuid.New()
|
||||
err = tx.InsertTemplate(ctx, database.InsertTemplateParams{
|
||||
ID: id,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
OrganizationID: organization.ID,
|
||||
@ -310,6 +301,11 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
return xerrors.Errorf("insert template: %s", err)
|
||||
}
|
||||
|
||||
dbTemplate, err = tx.GetTemplateByID(ctx, id)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get template by id: %s", err)
|
||||
}
|
||||
|
||||
dbTemplate, err = (*api.TemplateScheduleStore.Load()).SetTemplateScheduleOptions(ctx, tx, dbTemplate, schedule.TemplateScheduleOptions{
|
||||
UserAutostartEnabled: allowUserAutostart,
|
||||
UserAutostopEnabled: allowUserAutostop,
|
||||
@ -348,12 +344,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
templateVersionAudit.New = newTemplateVersion
|
||||
|
||||
createdByNameMap, err := getCreatedByNamesByTemplateIDs(ctx, tx, []database.Template{dbTemplate})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get creator name: %w", err)
|
||||
}
|
||||
|
||||
template = api.convertTemplate(dbTemplate, createdByNameMap[dbTemplate.ID.String()])
|
||||
template = api.convertTemplate(dbTemplate)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
@ -409,16 +400,7 @@ func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
createdByNameMap, err := getCreatedByNamesByTemplateIDs(ctx, api.Database, templates)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching creator names.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplates(templates, createdByNameMap))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplates(templates))
|
||||
}
|
||||
|
||||
// @Summary Get templates by organization and template name
|
||||
@ -451,16 +433,7 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
|
||||
createdByNameMap, err := getCreatedByNamesByTemplateIDs(ctx, api.Database, []database.Template{template})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching creator name.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(template, createdByNameMap[template.ID.String()]))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(template))
|
||||
}
|
||||
|
||||
// @Summary Update template metadata by ID
|
||||
@ -546,7 +519,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var err error
|
||||
updated, err = tx.UpdateTemplateMetaByID(ctx, database.UpdateTemplateMetaByIDParams{
|
||||
err = tx.UpdateTemplateMetaByID(ctx, database.UpdateTemplateMetaByIDParams{
|
||||
ID: template.ID,
|
||||
UpdatedAt: database.Now(),
|
||||
Name: name,
|
||||
@ -559,6 +532,11 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
return xerrors.Errorf("update template metadata: %w", err)
|
||||
}
|
||||
|
||||
updated, err = tx.GetTemplateByID(ctx, template.ID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("fetch updated template metadata: %w", err)
|
||||
}
|
||||
|
||||
defaultTTL := time.Duration(req.DefaultTTLMillis) * time.Millisecond
|
||||
maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond
|
||||
failureTTL := time.Duration(req.FailureTTLMillis) * time.Millisecond
|
||||
@ -603,16 +581,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
aReq.New = updated
|
||||
|
||||
createdByNameMap, err := getCreatedByNamesByTemplateIDs(ctx, api.Database, []database.Template{updated})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching creator name.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(updated, createdByNameMap[updated.ID.String()]))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(updated))
|
||||
}
|
||||
|
||||
// @Summary Get template DAUs by ID
|
||||
@ -680,23 +649,11 @@ func (api *API) templateExamples(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusOK, ex)
|
||||
}
|
||||
|
||||
func getCreatedByNamesByTemplateIDs(ctx context.Context, db database.Store, templates []database.Template) (map[string]string, error) {
|
||||
creators := make(map[string]string, len(templates))
|
||||
for _, template := range templates {
|
||||
creator, err := db.GetUserByID(ctx, template.CreatedBy)
|
||||
if err != nil {
|
||||
return map[string]string{}, err
|
||||
}
|
||||
creators[template.ID.String()] = creator.Username
|
||||
}
|
||||
return creators, nil
|
||||
}
|
||||
|
||||
func (api *API) convertTemplates(templates []database.Template, createdByNameMap map[string]string) []codersdk.Template {
|
||||
func (api *API) convertTemplates(templates []database.Template) []codersdk.Template {
|
||||
apiTemplates := make([]codersdk.Template, 0, len(templates))
|
||||
|
||||
for _, template := range templates {
|
||||
apiTemplates = append(apiTemplates, api.convertTemplate(template, createdByNameMap[template.ID.String()]))
|
||||
apiTemplates = append(apiTemplates, api.convertTemplate(template))
|
||||
}
|
||||
|
||||
// Sort templates by ActiveUserCount DESC
|
||||
@ -708,7 +665,7 @@ func (api *API) convertTemplates(templates []database.Template, createdByNameMap
|
||||
}
|
||||
|
||||
func (api *API) convertTemplate(
|
||||
template database.Template, createdByName string,
|
||||
template database.Template,
|
||||
) codersdk.Template {
|
||||
activeCount, _ := api.metricsCache.TemplateUniqueUsers(template.ID)
|
||||
|
||||
@ -730,7 +687,7 @@ func (api *API) convertTemplate(
|
||||
DefaultTTLMillis: time.Duration(template.DefaultTTL).Milliseconds(),
|
||||
MaxTTLMillis: time.Duration(template.MaxTTL).Milliseconds(),
|
||||
CreatedByID: template.CreatedBy,
|
||||
CreatedByName: createdByName,
|
||||
CreatedByName: template.CreatedByUsername,
|
||||
AllowUserAutostart: template.AllowUserAutostart,
|
||||
AllowUserAutostop: template.AllowUserAutostop,
|
||||
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
|
||||
|
Reference in New Issue
Block a user