Skip to content

Commit c0d2f6b

Browse files
authored
Fixes 4267,4269: add user to template (#699)
* Fixes 4267: add user to template * Fixes 4269: add created_at/updated_at to template response
1 parent 098cebb commit c0d2f6b

13 files changed

+136
-35
lines changed

api/docs.go

+16
Original file line numberDiff line numberDiff line change
@@ -3948,6 +3948,14 @@ const docTemplate = `{
39483948
"description": "Architecture of the template",
39493949
"type": "string"
39503950
},
3951+
"created_at": {
3952+
"description": "Datetime template was created",
3953+
"type": "string"
3954+
},
3955+
"created_by": {
3956+
"description": "User that created the template",
3957+
"type": "string"
3958+
},
39513959
"date": {
39523960
"description": "Latest date to include snapshots for",
39533961
"type": "string"
@@ -3956,6 +3964,10 @@ const docTemplate = `{
39563964
"description": "Description of the template",
39573965
"type": "string"
39583966
},
3967+
"last_updated_by": {
3968+
"description": "User that most recently updated the template",
3969+
"type": "string"
3970+
},
39593971
"name": {
39603972
"description": "Name of the template",
39613973
"type": "string"
@@ -3975,6 +3987,10 @@ const docTemplate = `{
39753987
"description": "Environment ID used by subscription-manager and candlepin",
39763988
"type": "string"
39773989
},
3990+
"updated_at": {
3991+
"description": "Datetime template was last updated",
3992+
"type": "string"
3993+
},
39783994
"uuid": {
39793995
"type": "string",
39803996
"readOnly": true

api/openapi.json

+16
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,14 @@
10721072
"description": "Architecture of the template",
10731073
"type": "string"
10741074
},
1075+
"created_at": {
1076+
"description": "Datetime template was created",
1077+
"type": "string"
1078+
},
1079+
"created_by": {
1080+
"description": "User that created the template",
1081+
"type": "string"
1082+
},
10751083
"date": {
10761084
"description": "Latest date to include snapshots for",
10771085
"type": "string"
@@ -1080,6 +1088,10 @@
10801088
"description": "Description of the template",
10811089
"type": "string"
10821090
},
1091+
"last_updated_by": {
1092+
"description": "User that most recently updated the template",
1093+
"type": "string"
1094+
},
10831095
"name": {
10841096
"description": "Name of the template",
10851097
"type": "string"
@@ -1099,6 +1111,10 @@
10991111
"description": "Environment ID used by subscription-manager and candlepin",
11001112
"type": "string"
11011113
},
1114+
"updated_at": {
1115+
"description": "Datetime template was last updated",
1116+
"type": "string"
1117+
},
11021118
"uuid": {
11031119
"readOnly": true,
11041120
"type": "string"

db/migrations.latest

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20240604140054
1+
20240610112037
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
BEGIN;
2+
3+
ALTER TABLE templates
4+
DROP COLUMN IF EXISTS created_by,
5+
DROP COLUMN IF EXISTS last_updated_by;
6+
7+
COMMIT;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
BEGIN;
2+
3+
ALTER TABLE templates
4+
ADD COLUMN IF NOT EXISTS created_by VARCHAR,
5+
ADD COLUMN IF NOT EXISTS last_updated_by VARCHAR;
6+
7+
COMMIT;

pkg/api/templates.go

+17-11
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import (
88

99
type TemplateRequest struct {
1010
UUID *string `json:"uuid" readonly:"true" swaggerignore:"true"`
11-
Name *string `json:"name"` // Name of the template
12-
Description *string `json:"description"` // Description of the template
13-
RepositoryUUIDS []string `json:"repository_uuids"` // Repositories to add to the template
14-
Arch *string `json:"arch"` // Architecture of the template
15-
Version *string `json:"version"` // Version of the template
16-
Date *time.Time `json:"date"` // Latest date to include snapshots for
17-
OrgID *string `json:"org_id" readonly:"true" swaggerignore:"true"` // Organization ID of the owner
11+
Name *string `json:"name"` // Name of the template
12+
Description *string `json:"description"` // Description of the template
13+
RepositoryUUIDS []string `json:"repository_uuids"` // Repositories to add to the template
14+
Arch *string `json:"arch"` // Architecture of the template
15+
Version *string `json:"version"` // Version of the template
16+
Date *time.Time `json:"date"` // Latest date to include snapshots for
17+
OrgID *string `json:"org_id" readonly:"true" swaggerignore:"true"` // Organization ID of the owner
18+
User *string `json:"created_by" readonly:"true" swaggerignore:"true"` // User creating the template
1819
}
1920

2021
type TemplateResponse struct {
@@ -27,15 +28,20 @@ type TemplateResponse struct {
2728
Date time.Time `json:"date"` // Latest date to include snapshots for
2829
RepositoryUUIDS []string `json:"repository_uuids"` // Repositories added to the template
2930
RHSMEnvironmentID string `json:"rhsm_environment_id"` // Environment ID used by subscription-manager and candlepin
31+
CreatedBy string `json:"created_by"` // User that created the template
32+
LastUpdatedBy string `json:"last_updated_by"` // User that most recently updated the template
33+
CreatedAt time.Time `json:"created_at"` // Datetime template was created
34+
UpdatedAt time.Time `json:"updated_at"` // Datetime template was last updated
3035
}
3136

3237
// We use a separate struct because name, version, arch cannot be updated
3338
type TemplateUpdateRequest struct {
3439
UUID *string `json:"uuid" readonly:"true" swaggerignore:"true"`
35-
Description *string `json:"description"` // Description of the template
36-
RepositoryUUIDS []string `json:"repository_uuids"` // Repositories to add to the template
37-
Date *time.Time `json:"date"` // Latest date to include snapshots for
38-
OrgID *string `json:"org_id" readonly:"true" swaggerignore:"true"` // Organization ID of the owner
40+
Description *string `json:"description"` // Description of the template
41+
RepositoryUUIDS []string `json:"repository_uuids"` // Repositories to add to the template
42+
Date *time.Time `json:"date"` // Latest date to include snapshots for
43+
OrgID *string `json:"org_id" readonly:"true" swaggerignore:"true"` // Organization ID of the owner
44+
User *string `json:"last_updated_by" readonly:"true" swaggerignore:"true"` // User creating the template
3945
}
4046

4147
type TemplateCollectionResponse struct {

pkg/dao/templates.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (t templateDaoImpl) create(ctx context.Context, tx *gorm.DB, reqTemplate ap
7070
}
7171

7272
// Create a template
73-
templatesApiToModel(reqTemplate, &modelTemplate)
73+
templatesCreateApiToModel(reqTemplate, &modelTemplate)
7474
err := tx.Create(&modelTemplate).Error
7575
if err != nil {
7676
return api.TemplateResponse{}, t.DBToApiError(err)
@@ -411,7 +411,7 @@ func (t templateDaoImpl) UpdateDistributionHrefs(ctx context.Context, templateUU
411411
return nil
412412
}
413413

414-
func templatesApiToModel(api api.TemplateRequest, model *models.Template) {
414+
func templatesCreateApiToModel(api api.TemplateRequest, model *models.Template) {
415415
if api.Name != nil {
416416
model.Name = *api.Name
417417
}
@@ -430,6 +430,10 @@ func templatesApiToModel(api api.TemplateRequest, model *models.Template) {
430430
if api.OrgID != nil {
431431
model.OrgID = *api.OrgID
432432
}
433+
if api.User != nil {
434+
model.CreatedBy = *api.User
435+
model.LastUpdatedBy = *api.User
436+
}
433437
}
434438

435439
func templatesUpdateApiToModel(api api.TemplateUpdateRequest, model *models.Template) {
@@ -442,6 +446,9 @@ func templatesUpdateApiToModel(api api.TemplateUpdateRequest, model *models.Temp
442446
if api.OrgID != nil {
443447
model.OrgID = *api.OrgID
444448
}
449+
if api.User != nil {
450+
model.LastUpdatedBy = *api.User
451+
}
445452
}
446453

447454
func templatesModelToApi(model models.Template, api *api.TemplateResponse) {
@@ -457,6 +464,10 @@ func templatesModelToApi(model models.Template, api *api.TemplateResponse) {
457464
for _, repoConfig := range model.RepositoryConfigurations {
458465
api.RepositoryUUIDS = append(api.RepositoryUUIDS, repoConfig.UUID)
459466
}
467+
api.CreatedBy = model.CreatedBy
468+
api.LastUpdatedBy = model.LastUpdatedBy
469+
api.CreatedAt = model.CreatedAt
470+
api.UpdatedAt = model.UpdatedAt
460471
}
461472

462473
func templatesConvertToResponses(templates []models.Template) []api.TemplateResponse {

pkg/dao/templates_test.go

+24-8
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (s *TemplateSuite) TestCreateDeleteCreateSameName() {
8181
Version: pointy.String(config.El8),
8282
Date: &timeNow,
8383
OrgID: &orgID,
84+
User: pointy.String("user"),
8485
}
8586

8687
respTemplate, err := templateDao.Create(context.Background(), reqTemplate)
@@ -105,6 +106,8 @@ func (s *TemplateSuite) TestCreateDeleteCreateSameName() {
105106
assert.Equal(s.T(), *reqTemplate.Arch, respTemplate.Arch)
106107
assert.Equal(s.T(), *reqTemplate.Version, respTemplate.Version)
107108
assert.Len(s.T(), reqTemplate.RepositoryUUIDS, 2)
109+
assert.Equal(s.T(), *reqTemplate.User, respTemplate.CreatedBy)
110+
assert.Equal(s.T(), *reqTemplate.User, respTemplate.LastUpdatedBy)
108111
}
109112

110113
func (s *TemplateSuite) TestFetch() {
@@ -122,6 +125,10 @@ func (s *TemplateSuite) TestFetch() {
122125
assert.Equal(s.T(), found.Name, resp.Name)
123126
assert.Equal(s.T(), found.OrgID, resp.OrgID)
124127
assert.Equal(s.T(), candlepin_client.GetEnvironmentID(resp.UUID), resp.RHSMEnvironmentID)
128+
assert.Equal(s.T(), found.LastUpdatedBy, resp.LastUpdatedBy)
129+
assert.Equal(s.T(), found.CreatedBy, resp.CreatedBy)
130+
assert.Equal(s.T(), found.CreatedAt, resp.CreatedAt)
131+
assert.Equal(s.T(), found.UpdatedAt, resp.UpdatedAt)
125132
}
126133

127134
func (s *TemplateSuite) TestFetchNotFound() {
@@ -151,18 +158,22 @@ func (s *TemplateSuite) TestList() {
151158
var found []models.Template
152159
var total int64
153160

154-
s.seedWithRepoConfig(orgIDTest)
161+
s.seedWithRepoConfig(orgIDTest, 1)
155162

156163
err = s.tx.Where("org_id = ?", orgIDTest).Find(&found).Count(&total).Error
157164
assert.NoError(s.T(), err)
158-
assert.Equal(s.T(), int64(2), total)
165+
assert.Equal(s.T(), int64(1), total)
159166

160167
responses, total, err := templateDao.List(context.Background(), orgIDTest, api.PaginationData{Limit: -1}, api.TemplateFilterData{})
161168
assert.NoError(s.T(), err)
162-
assert.Equal(s.T(), int64(2), total)
163-
assert.Len(s.T(), responses.Data, 2)
169+
assert.Equal(s.T(), int64(1), total)
170+
assert.Len(s.T(), responses.Data, 1)
164171
assert.Len(s.T(), responses.Data[0].RepositoryUUIDS, 2)
165172
assert.Equal(s.T(), candlepin_client.GetEnvironmentID(responses.Data[0].UUID), responses.Data[0].RHSMEnvironmentID)
173+
assert.Equal(s.T(), responses.Data[0].CreatedBy, found[0].CreatedBy)
174+
assert.Equal(s.T(), responses.Data[0].LastUpdatedBy, found[0].LastUpdatedBy)
175+
assert.Equal(s.T(), responses.Data[0].CreatedAt, found[0].CreatedAt)
176+
assert.Equal(s.T(), responses.Data[0].UpdatedAt, found[0].UpdatedAt)
166177
}
167178

168179
func (s *TemplateSuite) TestListNoTemplates() {
@@ -253,7 +264,7 @@ func (s *TemplateSuite) TestListFilters() {
253264
assert.Equal(s.T(), found[0].Arch, responses.Data[0].Arch)
254265

255266
// Test Filter by RepositoryUUIDs
256-
template, rcUUIDs := s.seedWithRepoConfig(orgIDTest)
267+
template, rcUUIDs := s.seedWithRepoConfig(orgIDTest, 2)
257268
filterData = api.TemplateFilterData{RepositoryUUIDs: []string{rcUUIDs[0]}}
258269
responses, total, err = templateDao.List(context.Background(), orgIDTest, api.PaginationData{Limit: -1}, filterData)
259270
assert.NoError(s.T(), err)
@@ -390,22 +401,22 @@ func (s *TemplateSuite) fetchTemplate(uuid string) models.Template {
390401
return found
391402
}
392403

393-
func (s *TemplateSuite) seedWithRepoConfig(orgId string) (models.Template, []string) {
404+
func (s *TemplateSuite) seedWithRepoConfig(orgId string, templateSize int) (models.Template, []string) {
394405
err := seeds.SeedRepositoryConfigurations(s.tx, 2, seeds.SeedOptions{OrgID: orgId})
395406
require.NoError(s.T(), err)
396407

397408
var rcUUIDs []string
398409
err = s.tx.Model(models.RepositoryConfiguration{}).Where("org_id = ?", orgIDTest).Select("uuid").Find(&rcUUIDs).Error
399410
require.NoError(s.T(), err)
400411

401-
templates, err := seeds.SeedTemplates(s.tx, 2, seeds.TemplateSeedOptions{OrgID: orgId, RepositoryConfigUUIDs: rcUUIDs})
412+
templates, err := seeds.SeedTemplates(s.tx, templateSize, seeds.TemplateSeedOptions{OrgID: orgId, RepositoryConfigUUIDs: rcUUIDs})
402413
require.NoError(s.T(), err)
403414

404415
return templates[0], rcUUIDs
405416
}
406417

407418
func (s *TemplateSuite) TestUpdate() {
408-
origTempl, rcUUIDs := s.seedWithRepoConfig(orgIDTest)
419+
origTempl, rcUUIDs := s.seedWithRepoConfig(orgIDTest, 2)
409420

410421
templateDao := templateDaoImpl{db: s.tx}
411422
_, err := templateDao.Update(context.Background(), orgIDTest, origTempl.UUID, api.TemplateUpdateRequest{Description: pointy.Pointer("scratch"), RepositoryUUIDS: []string{rcUUIDs[0]}})
@@ -424,6 +435,11 @@ func (s *TemplateSuite) TestUpdate() {
424435

425436
_, err = templateDao.Update(context.Background(), orgIDTest, found.UUID, api.TemplateUpdateRequest{RepositoryUUIDS: []string{"Notarealrepouuid"}})
426437
assert.Error(s.T(), err)
438+
439+
_, err = templateDao.Update(context.Background(), orgIDTest, found.UUID, api.TemplateUpdateRequest{RepositoryUUIDS: []string{rcUUIDs[1]}, User: pointy.Pointer("new user")})
440+
require.NoError(s.T(), err)
441+
found = s.fetchTemplate(origTempl.UUID)
442+
assert.Equal(s.T(), "new user", found.LastUpdatedBy)
427443
}
428444

429445
func (s *TemplateSuite) TestGetRepoChanges() {

pkg/handler/templates.go

+15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/content-services/content-sources-backend/pkg/tasks/queue"
1616
"github.com/google/uuid"
1717
"github.com/labstack/echo/v4"
18+
"github.com/redhatinsights/platform-go-middlewares/v2/identity"
1819
"github.com/rs/zerolog/log"
1920
)
2021

@@ -71,6 +72,9 @@ func (th *TemplateHandler) createTemplate(c echo.Context) error {
7172
_, orgID := getAccountIdOrgId(c)
7273
newTemplate.OrgID = &orgID
7374

75+
user := getUser(c)
76+
newTemplate.User = &user
77+
7478
respTemplate, err := th.DaoRegistry.Template.Create(c.Request().Context(), newTemplate)
7579
if err != nil {
7680
return ce.NewErrorResponse(ce.HttpCodeForDaoError(err), "Error creating template", err.Error())
@@ -187,6 +191,9 @@ func (th *TemplateHandler) update(c echo.Context, fillDefaults bool) error {
187191
tempParams := api.TemplateUpdateRequest{}
188192
_, orgID := getAccountIdOrgId(c)
189193

194+
user := getUser(c)
195+
tempParams.User = &user
196+
190197
if err := c.Bind(&tempParams); err != nil {
191198
return ce.NewErrorResponse(http.StatusBadRequest, "Error binding parameters", err.Error())
192199
}
@@ -303,3 +310,11 @@ func (th *TemplateHandler) enqueueUpdateTemplateContentEvent(c echo.Context, tem
303310
}
304311
return taskID
305312
}
313+
314+
func getUser(c echo.Context) string {
315+
id := identity.Get(c.Request().Context())
316+
if id.Identity.User != nil {
317+
return id.Identity.User.Username
318+
}
319+
return ""
320+
}

pkg/handler/templates_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ func (suite *TemplatesSuite) TestCreate() {
7676
Arch: pointy.Pointer(config.AARCH64),
7777
Version: pointy.Pointer(config.El8),
7878
OrgID: &orgID,
79+
User: pointy.Pointer("user"),
7980
}
8081

8182
expected := api.TemplateResponse{

pkg/models/template.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010

1111
type Template struct {
1212
Base
13-
Name string `gorm:"not null;default:null"`
14-
OrgID string `gorm:"default:null"`
15-
Description string `gorm:"default:null"`
16-
Date time.Time `gorm:"default:null"`
17-
Version string `gorm:"default:null"`
18-
Arch string `gorm:"default:null"`
19-
DeletedAt gorm.DeletedAt `json:"deleted_at"`
13+
Name string `gorm:"not null;default:null"`
14+
OrgID string `gorm:"default:null"`
15+
Description string `gorm:"default:null"`
16+
Date time.Time `gorm:"default:null"`
17+
Version string `gorm:"default:null"`
18+
Arch string `gorm:"default:null"`
19+
DeletedAt gorm.DeletedAt `json:"deleted_at"`
20+
CreatedBy string
21+
LastUpdatedBy string
2022
RepositoryConfigurations []RepositoryConfiguration `gorm:"many2many:templates_repository_configurations"`
2123
}
2224

@@ -61,5 +63,6 @@ func (t *Template) MapForUpdate() map[string]interface{} {
6163
// Name, version, arch cannot be updated
6264
forUpdate["description"] = t.Description
6365
forUpdate["date"] = t.Date
66+
forUpdate["last_updated_by"] = t.LastUpdatedBy
6467
return forUpdate
6568
}

pkg/seeds/seeds.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,14 @@ func SeedTemplates(db *gorm.DB, size int, options TemplateSeedOptions) ([]models
224224
Base: models.Base{
225225
UUID: uuid.NewString(),
226226
},
227-
Name: RandStringBytes(10),
228-
OrgID: orgID,
229-
Description: "description",
230-
Date: time.Now(),
231-
Version: createVersion(options.Version),
232-
Arch: createArch(options.Arch),
227+
Name: RandStringBytes(10),
228+
OrgID: orgID,
229+
Description: "description",
230+
Date: time.Now(),
231+
Version: createVersion(options.Version),
232+
Arch: createArch(options.Arch),
233+
CreatedBy: "user",
234+
LastUpdatedBy: "user",
233235
}
234236
err := db.Create(&t).Error
235237
if err != nil {

pkg/test/handler/utils.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var MockIdentity = identity.XRHID{
1717
Internal: identity.Internal{
1818
OrgID: MockOrgId,
1919
},
20+
User: &identity.User{Username: "user"},
2021
Type: "Associate",
2122
},
2223
}

0 commit comments

Comments
 (0)