diff --git a/api/group.go b/api/group.go index a1d39c9..f8580af 100755 --- a/api/group.go +++ b/api/group.go @@ -18,6 +18,7 @@ type Group struct { Org string `json:"org, omitempty"` Urn string `json:"urn, omitempty"` CreateAt time.Time `json:"createAt, omitempty"` + UpdateAt time.Time `json:"updateAt, omitempty"` } func (g Group) String() string { @@ -254,15 +255,14 @@ func (api AuthAPI) UpdateGroup(requestInfo RequestInfo, org string, name string, } } - // Call repo to retrieve the group - group, err := api.GetGroupByName(requestInfo, org, name) + // Call repo to retrieve the old group + oldGroup, err := api.GetGroupByName(requestInfo, org, name) if err != nil { return nil, err } - oldGroup := group // Check restrictions - groupsFiltered, err := api.GetAuthorizedGroups(requestInfo, group.Urn, GROUP_ACTION_UPDATE_GROUP, []Group{*group}) + groupsFiltered, err := api.GetAuthorizedGroups(requestInfo, oldGroup.Urn, GROUP_ACTION_UPDATE_GROUP, []Group{*oldGroup}) if err != nil { return nil, err } @@ -270,14 +270,14 @@ func (api AuthAPI) UpdateGroup(requestInfo RequestInfo, org string, name string, return nil, &Error{ Code: UNAUTHORIZED_RESOURCES_ERROR, Message: fmt.Sprintf("User with externalId %v is not allowed to access to resource %v", - requestInfo.Identifier, group.Urn), + requestInfo.Identifier, oldGroup.Urn), } } // Check if a group with "newName" already exists newGroup, err := api.GetGroupByName(requestInfo, org, newName) - if err == nil && group.ID != newGroup.ID { + if err == nil && oldGroup.ID != newGroup.ID { // Group already exists return nil, &Error{ Code: GROUP_ALREADY_EXIST, @@ -286,16 +286,17 @@ func (api AuthAPI) UpdateGroup(requestInfo RequestInfo, org string, name string, } if err != nil { - if apiError := err.(*Error); apiError.Code == UNAUTHORIZED_RESOURCES_ERROR || apiError.Code == UNKNOWN_API_ERROR { + if apiError := err.(*Error); apiError.Code != GROUP_BY_ORG_AND_NAME_NOT_FOUND { return nil, err } } - // Get Group updated - groupToUpdate := createGroup(org, newName, newPath) + auxGroup := Group{ + Urn: CreateUrn(org, RESOURCE_GROUP, newPath, newName), + } // Check restrictions - groupsFiltered, err = api.GetAuthorizedGroups(requestInfo, groupToUpdate.Urn, GROUP_ACTION_UPDATE_GROUP, []Group{groupToUpdate}) + groupsFiltered, err = api.GetAuthorizedGroups(requestInfo, auxGroup.Urn, GROUP_ACTION_UPDATE_GROUP, []Group{auxGroup}) if err != nil { return nil, err } @@ -303,12 +304,22 @@ func (api AuthAPI) UpdateGroup(requestInfo RequestInfo, org string, name string, return nil, &Error{ Code: UNAUTHORIZED_RESOURCES_ERROR, Message: fmt.Sprintf("User with externalId %v is not allowed to access to resource %v", - requestInfo.Identifier, groupToUpdate.Urn), + requestInfo.Identifier, auxGroup.Urn), } } // Update group - group, err = api.GroupRepo.UpdateGroup(*group, newName, newPath, groupToUpdate.Urn) + group := Group{ + ID: oldGroup.ID, + Name: newName, + Path: newPath, + Org: oldGroup.Org, + Urn: auxGroup.Urn, + CreateAt: oldGroup.CreateAt, + UpdateAt: time.Now().UTC(), + } + + updatedGroup, err := api.GroupRepo.UpdateGroup(group) // Check unexpected DB error if err != nil { @@ -320,8 +331,8 @@ func (api AuthAPI) UpdateGroup(requestInfo RequestInfo, org string, name string, } } - LogOperation(api.Logger, requestInfo, fmt.Sprintf("Group updated from %+v to %+v", oldGroup, group)) - return group, nil + LogOperation(api.Logger, requestInfo, fmt.Sprintf("Group updated from %+v to %+v", oldGroup, updatedGroup)) + return updatedGroup, nil } @@ -725,6 +736,7 @@ func createGroup(org string, name string, path string) Group { Name: name, Path: path, CreateAt: time.Now().UTC(), + UpdateAt: time.Now().UTC(), Urn: urn, Org: org, } diff --git a/api/manager.go b/api/manager.go index a4e6543..b588cde 100644 --- a/api/manager.go +++ b/api/manager.go @@ -161,9 +161,9 @@ type UserRepo interface { // if there are problems with database. GetUsersFiltered(filter *Filter) ([]User, int, error) - // Update user stored in database with new pathPrefix. Throw error if the database restrictions + // Update user stored in database with new fields. Throw error if the database restrictions // are not satisfied or unexpected error happen. - UpdateUser(user User, newPath string, newUrn string) (*User, error) + UpdateUser(user User) (*User, error) // Remove user stored in database with its group relationships. // Throw error if there are problems during transactions. @@ -186,9 +186,9 @@ type GroupRepo interface { // if there are problems with database. GetGroupsFiltered(org string, filter *Filter) ([]Group, int, error) - // Update group stored in database with new name and pathPrefix. + // Update group stored in database with new fields. // Throw error if there are problems with database. - UpdateGroup(group Group, newName string, newPath string, newUrn string) (*Group, error) + UpdateGroup(group Group) (*Group, error) // Remove group stored in database with its user and policy relationships. // Throw error if there are problems during transactions. @@ -237,9 +237,9 @@ type PolicyRepo interface { // if there are problems with database. GetPoliciesFiltered(org string, filter *Filter) ([]Policy, int, error) - // Update policy stored in database with new name and pathPrefix. Also it overrides statements. + // Update policy stored in database with new fields. Also it overrides statements if it has. // Throw error if there are problems with database. - UpdatePolicy(policy Policy, newName string, newPath string, newUrn string, newStatements []Statement) (*Policy, error) + UpdatePolicy(policy Policy) (*Policy, error) // Remove policy stored in database with its groups relationships. // Throw error if there are problems during transactions. diff --git a/api/policy.go b/api/policy.go index 7ea1f4d..a3f381f 100755 --- a/api/policy.go +++ b/api/policy.go @@ -18,6 +18,7 @@ type Policy struct { Org string `json:"org, omitempty"` Urn string `json:"urn, omitempty"` CreateAt time.Time `json:"createAt, omitempty"` + UpdateAt time.Time `json:"updateAt, omitempty"` Statements *[]Statement `json:"statements, omitempty"` } @@ -278,14 +279,14 @@ func (api AuthAPI) UpdatePolicy(requestInfo RequestInfo, org string, policyName } - // Call repo to retrieve the policy - policyDB, err := api.GetPolicyByName(requestInfo, org, policyName) + // Call repo to retrieve the old policy + oldPolicy, err := api.GetPolicyByName(requestInfo, org, policyName) if err != nil { return nil, err } // Check restrictions - policiesFiltered, err := api.GetAuthorizedPolicies(requestInfo, policyDB.Urn, POLICY_ACTION_UPDATE_POLICY, []Policy{*policyDB}) + policiesFiltered, err := api.GetAuthorizedPolicies(requestInfo, oldPolicy.Urn, POLICY_ACTION_UPDATE_POLICY, []Policy{*oldPolicy}) if err != nil { return nil, err } @@ -293,31 +294,33 @@ func (api AuthAPI) UpdatePolicy(requestInfo RequestInfo, org string, policyName return nil, &Error{ Code: UNAUTHORIZED_RESOURCES_ERROR, Message: fmt.Sprintf("User with externalId %v is not allowed to access to resource %v", - requestInfo.Identifier, policyDB.Urn), + requestInfo.Identifier, oldPolicy.Urn), } } // Check if policy with "newName" exists targetPolicy, err := api.GetPolicyByName(requestInfo, org, newName) - if err == nil && targetPolicy.ID != policyDB.ID { + if err == nil && targetPolicy.ID != oldPolicy.ID { // Policy already exists return nil, &Error{ Code: POLICY_ALREADY_EXIST, Message: fmt.Sprintf("Policy name: %v already exists", newName), } } + if err != nil { - if apiError := err.(*Error); apiError.Code == UNAUTHORIZED_RESOURCES_ERROR || apiError.Code == UNKNOWN_API_ERROR { + if apiError := err.(*Error); apiError.Code != POLICY_BY_ORG_AND_NAME_NOT_FOUND { return nil, err } } - // Get Policy Updated - policyToUpdate := createPolicy(newName, newPath, org, &newStatements) + auxPolicy := Policy{ + Urn: CreateUrn(org, RESOURCE_POLICY, newPath, newName), + } // Check restrictions - policiesFiltered, err = api.GetAuthorizedPolicies(requestInfo, policyToUpdate.Urn, POLICY_ACTION_UPDATE_POLICY, []Policy{policyToUpdate}) + policiesFiltered, err = api.GetAuthorizedPolicies(requestInfo, auxPolicy.Urn, POLICY_ACTION_UPDATE_POLICY, []Policy{auxPolicy}) if err != nil { return nil, err } @@ -325,12 +328,23 @@ func (api AuthAPI) UpdatePolicy(requestInfo RequestInfo, org string, policyName return nil, &Error{ Code: UNAUTHORIZED_RESOURCES_ERROR, Message: fmt.Sprintf("User with externalId %v is not allowed to access to resource %v", - requestInfo.Identifier, policyToUpdate.Urn), + requestInfo.Identifier, auxPolicy.Urn), } } + policy := Policy{ + ID: oldPolicy.ID, + Name: newName, + Path: newPath, + Org: oldPolicy.Org, + Urn: auxPolicy.Urn, + CreateAt: oldPolicy.CreateAt, + UpdateAt: time.Now().UTC(), + Statements: &newStatements, + } + // Update policy - policy, err := api.PolicyRepo.UpdatePolicy(*policyDB, newName, newPath, policyToUpdate.Urn, newStatements) + updatedPolicy, err := api.PolicyRepo.UpdatePolicy(policy) // Check unexpected DB error if err != nil { @@ -342,8 +356,8 @@ func (api AuthAPI) UpdatePolicy(requestInfo RequestInfo, org string, policyName } } - LogOperation(api.Logger, requestInfo, fmt.Sprintf("Policy updated from %+v to %+v", policyDB, policy)) - return policy, nil + LogOperation(api.Logger, requestInfo, fmt.Sprintf("Policy updated from %+v to %+v", oldPolicy, updatedPolicy)) + return updatedPolicy, nil } func (api AuthAPI) RemovePolicy(requestInfo RequestInfo, org string, name string) error { @@ -443,9 +457,10 @@ func createPolicy(name string, path string, org string, statements *[]Statement) ID: uuid.NewV4().String(), Name: name, Path: path, + CreateAt: time.Now().UTC(), + UpdateAt: time.Now().UTC(), Org: org, Urn: urn, - CreateAt: time.Now().UTC(), Statements: statements, } diff --git a/api/testutils_test.go b/api/testutils_test.go index 09f02ed..10bc0a1 100644 --- a/api/testutils_test.go +++ b/api/testutils_test.go @@ -159,10 +159,8 @@ func (t TestRepo) AddUser(user User) (*User, error) { return created, err } -func (t TestRepo) UpdateUser(user User, newPath string, newUrn string) (*User, error) { +func (t TestRepo) UpdateUser(user User) (*User, error) { t.ArgsIn[UpdateUserMethod][0] = user - t.ArgsIn[UpdateUserMethod][1] = newPath - t.ArgsIn[UpdateUserMethod][2] = newUrn var updated *User if t.ArgsOut[UpdateUserMethod][0] != nil { updated = t.ArgsOut[UpdateUserMethod][0].(*User) @@ -363,11 +361,8 @@ func (t TestRepo) RemoveMember(userID string, groupID string) error { return err } -func (t TestRepo) UpdateGroup(group Group, newName string, newPath string, newUrn string) (*Group, error) { +func (t TestRepo) UpdateGroup(group Group) (*Group, error) { t.ArgsIn[UpdateGroupMethod][0] = group - t.ArgsIn[UpdateGroupMethod][1] = newName - t.ArgsIn[UpdateGroupMethod][2] = newPath - t.ArgsIn[UpdateGroupMethod][3] = newUrn var updated *Group if t.ArgsOut[UpdateGroupMethod][0] != nil { @@ -433,12 +428,8 @@ func (t TestRepo) AddPolicy(policy Policy) (*Policy, error) { return created, err } -func (t TestRepo) UpdatePolicy(policy Policy, newName string, newPath string, newUrn string, newStatements []Statement) (*Policy, error) { +func (t TestRepo) UpdatePolicy(policy Policy) (*Policy, error) { t.ArgsIn[UpdatePolicyMethod][0] = policy - t.ArgsIn[UpdatePolicyMethod][1] = newName - t.ArgsIn[UpdatePolicyMethod][2] = newPath - t.ArgsIn[UpdatePolicyMethod][3] = newUrn - t.ArgsIn[UpdatePolicyMethod][4] = newStatements var updated *Policy if t.ArgsOut[UpdatePolicyMethod][0] != nil { diff --git a/api/user.go b/api/user.go index 5b1116f..05be3a7 100755 --- a/api/user.go +++ b/api/user.go @@ -17,6 +17,7 @@ type User struct { Path string `json:"path, omitempty"` Urn string `json:"urn, omitempty"` CreateAt time.Time `json:"createAt, omitempty"` + UpdateAt time.Time `json:"updateAt, omitempty"` } func (u User) String() string { @@ -203,13 +204,13 @@ func (api AuthAPI) UpdateUser(requestInfo RequestInfo, externalId string, newPat } // Call repo to retrieve the user - userDB, err := api.GetUserByExternalID(requestInfo, externalId) + oldUser, err := api.GetUserByExternalID(requestInfo, externalId) if err != nil { return nil, err } // Check restrictions - usersFiltered, err := api.GetAuthorizedUsers(requestInfo, userDB.Urn, USER_ACTION_UPDATE_USER, []User{*userDB}) + usersFiltered, err := api.GetAuthorizedUsers(requestInfo, oldUser.Urn, USER_ACTION_UPDATE_USER, []User{*oldUser}) if err != nil { return nil, err } @@ -217,14 +218,16 @@ func (api AuthAPI) UpdateUser(requestInfo RequestInfo, externalId string, newPat return nil, &Error{ Code: UNAUTHORIZED_RESOURCES_ERROR, Message: fmt.Sprintf("User with externalId %v is not allowed to access to resource %v", - requestInfo.Identifier, userDB.Urn), + requestInfo.Identifier, oldUser.Urn), } } - userToUpdate := createUser(externalId, newPath) + auxUser := User{ + Urn: CreateUrn("", RESOURCE_USER, newPath, externalId), + } // Check restrictions - usersFiltered, err = api.GetAuthorizedUsers(requestInfo, userToUpdate.Urn, USER_ACTION_GET_USER, []User{userToUpdate}) + usersFiltered, err = api.GetAuthorizedUsers(requestInfo, auxUser.Urn, USER_ACTION_GET_USER, []User{auxUser}) if err != nil { return nil, err } @@ -232,11 +235,20 @@ func (api AuthAPI) UpdateUser(requestInfo RequestInfo, externalId string, newPat return nil, &Error{ Code: UNAUTHORIZED_RESOURCES_ERROR, Message: fmt.Sprintf("User with externalId %v is not allowed to access to resource %v", - requestInfo.Identifier, userToUpdate.Urn), + requestInfo.Identifier, auxUser.Urn), } } - user, err := api.UserRepo.UpdateUser(*userDB, newPath, userToUpdate.Urn) + user := User{ + ID: oldUser.ID, + ExternalID: oldUser.ExternalID, + Path: newPath, + CreateAt: oldUser.CreateAt, + UpdateAt: time.Now().UTC(), + Urn: auxUser.Urn, + } + + updatedUser, err := api.UserRepo.UpdateUser(user) // Check unexpected DB error if err != nil { @@ -248,8 +260,8 @@ func (api AuthAPI) UpdateUser(requestInfo RequestInfo, externalId string, newPat } } - LogOperation(api.Logger, requestInfo, fmt.Sprintf("User updated from %+v to %+v", userDB, user)) - return user, nil + LogOperation(api.Logger, requestInfo, fmt.Sprintf("User updated from %+v to %+v", oldUser, updatedUser)) + return updatedUser, nil } @@ -355,6 +367,7 @@ func createUser(externalId string, path string) User { ExternalID: externalId, Path: path, CreateAt: time.Now().UTC(), + UpdateAt: time.Now().UTC(), Urn: urn, } diff --git a/database/postgresql/group.go b/database/postgresql/group.go index 2aba52d..7741c39 100644 --- a/database/postgresql/group.go +++ b/database/postgresql/group.go @@ -18,6 +18,7 @@ func (g PostgresRepo) AddGroup(group api.Group) (*api.Group, error) { Name: group.Name, Path: group.Path, CreateAt: group.CreateAt.UnixNano(), + UpdateAt: group.UpdateAt.UnixNano(), Urn: group.Urn, Org: group.Org, } @@ -107,33 +108,26 @@ func (g PostgresRepo) GetGroupsFiltered(org string, filter *api.Filter) ([]api.G for i, g := range groups { apiGroups[i] = *dbGroupToAPIGroup(&g) } - return apiGroups, total, nil } // No data to return return apiGroups, total, nil } -func (g PostgresRepo) UpdateGroup(group api.Group, newName string, newPath string, urn string) (*api.Group, error) { - - // Create new group - updatedGroup := Group{ - Name: newName, - Path: newPath, - Urn: urn, - } +func (g PostgresRepo) UpdateGroup(group api.Group) (*api.Group, error) { groupDB := Group{ ID: group.ID, Name: group.Name, Path: group.Path, CreateAt: group.CreateAt.UTC().UnixNano(), + UpdateAt: group.UpdateAt.UTC().UnixNano(), Urn: group.Urn, Org: group.Org, } // Update group - query := g.Dbmap.Model(&groupDB).Update(updatedGroup) + query := g.Dbmap.Model(&Group{ID: group.ID}).Updates(groupDB) // Check if group exist if query.RecordNotFound() { @@ -151,7 +145,7 @@ func (g PostgresRepo) UpdateGroup(group api.Group, newName string, newPath strin } } - return dbGroupToAPIGroup(&groupDB), nil + return &group, nil } func (g PostgresRepo) RemoveGroup(id string) error { @@ -371,6 +365,7 @@ func dbGroupToAPIGroup(groupdb *Group) *api.Group { Name: groupdb.Name, Path: groupdb.Path, CreateAt: time.Unix(0, groupdb.CreateAt).UTC(), + UpdateAt: time.Unix(0, groupdb.UpdateAt).UTC(), Urn: groupdb.Urn, Org: groupdb.Org, } diff --git a/database/postgresql/group_test.go b/database/postgresql/group_test.go index 514de4e..4685e8e 100644 --- a/database/postgresql/group_test.go +++ b/database/postgresql/group_test.go @@ -13,7 +13,7 @@ func TestPostgresRepo_AddGroup(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousGroup *api.Group + previousGroup *Group // Postgres Repo Args groupToCreate *api.Group // Expected result @@ -27,6 +27,7 @@ func TestPostgresRepo_AddGroup(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, Org: "Org", }, expectedResponse: &api.Group{ @@ -35,16 +36,18 @@ func TestPostgresRepo_AddGroup(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, Org: "Org", }, }, "ErrorCasegroupAlreadyExist": { - previousGroup: &api.Group{ + previousGroup: &Group{ ID: "GroupID", Name: "Name", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, groupToCreate: &api.Group{ @@ -53,6 +56,7 @@ func TestPostgresRepo_AddGroup(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, Org: "Org", }, expectedError: &database.Error{ @@ -68,8 +72,7 @@ func TestPostgresRepo_AddGroup(t *testing.T) { // Insert previous data if test.previousGroup != nil { - err := insertGroup(test.previousGroup.ID, test.previousGroup.Name, test.previousGroup.Path, - test.previousGroup.CreateAt.UnixNano(), test.previousGroup.Urn, test.previousGroup.Org) + err := insertGroup(*test.previousGroup) if err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue @@ -99,7 +102,7 @@ func TestPostgresRepo_AddGroup(t *testing.T) { } // Check database groupNumber, err := getGroupsCountFiltered(test.groupToCreate.ID, test.groupToCreate.Name, test.groupToCreate.Path, - test.groupToCreate.CreateAt.UnixNano(), test.groupToCreate.Urn, test.groupToCreate.Org) + test.groupToCreate.CreateAt.UnixNano(), test.groupToCreate.UpdateAt.UnixNano(), test.groupToCreate.Urn, test.groupToCreate.Org) if err != nil { t.Errorf("Test %v failed. Unexpected error counting groups: %v", n, err) continue @@ -116,7 +119,7 @@ func TestPostgresRepo_GetGroupByName(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousGroup *api.Group + previousGroup *Group // Postgres Repo Args org string name string @@ -125,12 +128,13 @@ func TestPostgresRepo_GetGroupByName(t *testing.T) { expectedError *database.Error }{ "OkCase": { - previousGroup: &api.Group{ + previousGroup: &Group{ ID: "GroupID", Name: "Name", Path: "Path", Urn: "Urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, org: "Org", @@ -141,16 +145,18 @@ func TestPostgresRepo_GetGroupByName(t *testing.T) { Path: "Path", Urn: "Urn", CreateAt: now, + UpdateAt: now, Org: "Org", }, }, "ErrorCaseGroupNotExist": { - previousGroup: &api.Group{ + previousGroup: &Group{ ID: "GroupID", Name: "Name", Path: "Path", Urn: "Urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, org: "Org", @@ -168,8 +174,7 @@ func TestPostgresRepo_GetGroupByName(t *testing.T) { // Insert previous data if test.previousGroup != nil { - err := insertGroup(test.previousGroup.ID, test.previousGroup.Name, test.previousGroup.Path, - test.previousGroup.CreateAt.UnixNano(), test.previousGroup.Urn, test.previousGroup.Org) + err := insertGroup(*test.previousGroup) if err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue @@ -202,7 +207,7 @@ func TestPostgresRepo_GetGroupById(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousGroup *api.Group + previousGroup *Group // Postgres Repo Args groupID string // Expected result @@ -210,12 +215,13 @@ func TestPostgresRepo_GetGroupById(t *testing.T) { expectedError *database.Error }{ "OkCase": { - previousGroup: &api.Group{ + previousGroup: &Group{ ID: "GroupID", Name: "Name", Path: "Path", Urn: "Urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, groupID: "GroupID", @@ -225,16 +231,18 @@ func TestPostgresRepo_GetGroupById(t *testing.T) { Path: "Path", Urn: "Urn", CreateAt: now, + UpdateAt: now, Org: "Org", }, }, "ErrorCaseGroupNotExist": { - previousGroup: &api.Group{ + previousGroup: &Group{ ID: "GroupID", Name: "Name", Path: "Path", Urn: "Urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, groupID: "NotExist", @@ -251,8 +259,7 @@ func TestPostgresRepo_GetGroupById(t *testing.T) { // Insert previous data if test.previousGroup != nil { - err := insertGroup(test.previousGroup.ID, test.previousGroup.Name, test.previousGroup.Path, - test.previousGroup.CreateAt.UnixNano(), test.previousGroup.Urn, test.previousGroup.Org) + err := insertGroup(*test.previousGroup) if err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue @@ -285,7 +292,7 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousGroups []api.Group + previousGroups []Group // Postgres Repo Args org string filter *api.Filter @@ -293,13 +300,14 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { expectedResponse []api.Group }{ "OkCasePathPrefix1": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org1", }, { @@ -307,7 +315,8 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Name: "Name2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -323,6 +332,7 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, Org: "Org1", }, { @@ -331,18 +341,20 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path456", Urn: "urn2", CreateAt: now, + UpdateAt: now, Org: "Org2", }, }, }, "OkCasePathPrefix2": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org1", }, { @@ -350,7 +362,8 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Name: "Name2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -366,18 +379,20 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, Org: "Org1", }, }, }, "OkCasePathPrefix3": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org1", }, { @@ -385,7 +400,8 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Name: "Name2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -397,13 +413,14 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { expectedResponse: []api.Group{}, }, "OkCaseGetByOrg": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org1", }, { @@ -411,7 +428,8 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Name: "Name2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -424,18 +442,20 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, Org: "Org1", }, }, }, "OkCaseGetByOrgAndPathPrefix": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org1", }, { @@ -443,7 +463,8 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Name: "Name2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -460,18 +481,20 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, Org: "Org1", }, }, }, "OkCaseWithoutParams": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org1", }, { @@ -479,7 +502,8 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Name: "Name2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -491,6 +515,7 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, Org: "Org1", }, { @@ -499,6 +524,7 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { Path: "Path456", Urn: "urn2", CreateAt: now, + UpdateAt: now, Org: "Org2", }, }, @@ -512,8 +538,7 @@ func TestPostgresRepo_GetGroupsFiltered(t *testing.T) { // Insert previous data if test.previousGroups != nil { for _, previousGroup := range test.previousGroups { - if err := insertGroup(previousGroup.ID, previousGroup.Name, previousGroup.Path, - previousGroup.CreateAt.UnixNano(), previousGroup.Urn, previousGroup.Org); err != nil { + if err := insertGroup(previousGroup); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous groups: %v", n, err) continue } @@ -542,55 +567,53 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousGroups []api.Group + previousGroups []Group // Postgres Repo Args groupToUpdate *api.Group - newName string - newPath string - newUrn string // Expected result expectedResponse *api.Group expectedError *database.Error }{ "OkCase": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID", Name: "Name", Path: "Path", Urn: "Urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, }, groupToUpdate: &api.Group{ ID: "GroupID", - Name: "Name", - Path: "Path", - Urn: "Urn", + Name: "NewName", + Path: "NewPath", + Urn: "NewUrn", CreateAt: now, + UpdateAt: now, Org: "Org", }, - newName: "NewName", - newPath: "NewPath", - newUrn: "NewUrn", expectedResponse: &api.Group{ ID: "GroupID", Name: "NewName", Path: "NewPath", Urn: "NewUrn", CreateAt: now, + UpdateAt: now, Org: "Org", }, }, "ErrorCaseDuplicateUrn": { - previousGroups: []api.Group{ + previousGroups: []Group{ { ID: "GroupID", Name: "Name", Path: "Path", Urn: "Urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, { @@ -598,7 +621,8 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { Name: "Name2", Path: "Path2", Urn: "Fail", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org2", }, }, @@ -606,13 +630,10 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { ID: "GroupID", Name: "Name", Path: "Path", - Urn: "Urn", + Urn: "Fail", CreateAt: now, Org: "Org", }, - newName: "NewName", - newPath: "NewPath", - newUrn: "Fail", expectedError: &database.Error{ Code: database.INTERNAL_ERROR, Message: "pq: duplicate key value violates unique constraint \"groups_urn_key\"", @@ -627,8 +648,7 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { // Insert previous data if test.previousGroups != nil { for _, previousGroup := range test.previousGroups { - err := insertGroup(previousGroup.ID, previousGroup.Name, previousGroup.Path, - previousGroup.CreateAt.UnixNano(), previousGroup.Urn, previousGroup.Org) + err := insertGroup(previousGroup) if err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue @@ -637,7 +657,7 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { } // Call to repository to update group - updatedGroup, err := repoDB.UpdateGroup(*test.groupToUpdate, test.newName, test.newPath, test.newUrn) + updatedGroup, err := repoDB.UpdateGroup(*test.groupToUpdate) if test.expectedError != nil { dbError, ok := err.(*database.Error) if !ok || dbError == nil { @@ -660,7 +680,8 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { } // Check database groupNumber, err := getGroupsCountFiltered(test.expectedResponse.ID, test.expectedResponse.Name, test.expectedResponse.Path, - test.expectedResponse.CreateAt.UnixNano(), test.expectedResponse.Urn, test.expectedResponse.Org) + test.expectedResponse.CreateAt.UnixNano(), test.expectedResponse.UpdateAt.UnixNano(), test.expectedResponse.Urn, + test.expectedResponse.Org) if err != nil { t.Errorf("Test %v failed. Unexpected error counting groups: %v", n, err) continue @@ -676,29 +697,47 @@ func TestPostgresRepo_UpdateGroup(t *testing.T) { func TestPostgresRepo_RemoveGroup(t *testing.T) { type relation struct { userID string - groupIDs []string + groupID string groupNotFound bool } now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousGroup *api.Group - relation *relation + previousGroups []Group + relations []relation // Postgres Repo Args groupToDelete string }{ "OkCase": { - previousGroup: &api.Group{ - ID: "GroupID", - Name: "Name", - Path: "Path", - Urn: "Urn", - CreateAt: now, - Org: "Org", + previousGroups: []Group{ + { + ID: "GroupID", + Name: "Name", + Path: "Path", + Urn: "Urn", + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), + Org: "Org", + }, + { + ID: "GroupID2", + Name: "Name", + Path: "Path", + Urn: "Urn2", + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), + Org: "Org", + }, }, - relation: &relation{ - userID: "UserID", - groupIDs: []string{"GroupID"}, + relations: []relation{ + { + userID: "UserID", + groupID: "GroupID", + }, + { + userID: "UserID", + groupID: "GroupID2", + }, }, groupToDelete: "GroupID", }, @@ -709,16 +748,17 @@ func TestPostgresRepo_RemoveGroup(t *testing.T) { cleanGroupUserRelationTable() // Insert previous data - if test.previousGroup != nil { - if err := insertGroup(test.previousGroup.ID, test.previousGroup.Name, test.previousGroup.Path, - test.previousGroup.CreateAt.Unix(), test.previousGroup.Urn, test.previousGroup.Org); err != nil { - t.Errorf("Test %v failed. Unexpected error inserting previous group: %v", n, err) - continue + if test.previousGroups != nil { + for _, g := range test.previousGroups { + if err := insertGroup(g); err != nil { + t.Errorf("Test %v failed. Unexpected error inserting previous group %v: %v", n, g.ID, err) + continue + } } } - if test.relation != nil { - for _, id := range test.relation.groupIDs { - if err := insertGroupUserRelation(test.relation.userID, id); err != nil { + if test.relations != nil { + for _, rel := range test.relations { + if err := insertGroupUserRelation(rel.userID, rel.groupID); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous group user relations: %v", n, err) continue } @@ -728,8 +768,7 @@ func TestPostgresRepo_RemoveGroup(t *testing.T) { err := repoDB.RemoveGroup(test.groupToDelete) // Check database - groupNumber, err := getGroupsCountFiltered(test.groupToDelete, "", "", - 0, "", "") + groupNumber, err := getGroupsCountFiltered(test.groupToDelete, "", "", 0, 0, "", "") if err != nil { t.Errorf("Test %v failed. Unexpected error counting groups: %v", n, err) continue @@ -739,13 +778,36 @@ func TestPostgresRepo_RemoveGroup(t *testing.T) { continue } - relations, err := getGroupUserRelations(test.previousGroup.ID, "") + // Check total groups + totalGroupNumber, err := getGroupsCountFiltered("", "", "", 0, 0, "", "") if err != nil { - t.Errorf("Test %v failed. Unexpected error counting relations: %v", n, err) + t.Errorf("Test %v failed. Unexpected error counting total groups: %v", n, err) + continue + } + if totalGroupNumber != 1 { + t.Errorf("Test %v failed. Received different total group number: %v", n, totalGroupNumber) + continue + } + + // Check group user relations + relations, err := getGroupUserRelations(test.groupToDelete, "") + if err != nil { + t.Errorf("Test %v failed. Unexpected error counting group user relations: %v", n, err) continue } if relations != 0 { - t.Errorf("Test %v failed. Received different relations number: %v", n, relations) + t.Errorf("Test %v failed. Received different group user relation number: %v", n, relations) + continue + } + + // Check total group user relations + totalRelations, err := getGroupUserRelations("", "") + if err != nil { + t.Errorf("Test %v failed. Unexpected error counting total relations: %v", n, err) + continue + } + if relations != 0 { + t.Errorf("Test %v failed. Received different total group user relation number: %v", n, totalRelations) continue } } @@ -918,7 +980,7 @@ func TestPostgresRepo_IsMemberOfGroup(t *testing.T) { func TestPostgresRepo_GetGroupMembers(t *testing.T) { type relations struct { - users []api.User + users []User groupID string userNotFound bool } @@ -935,20 +997,22 @@ func TestPostgresRepo_GetGroupMembers(t *testing.T) { }{ "OkCase": { relations: &relations{ - users: []api.User{ + users: []User{ { ID: "UserID1", ExternalID: "ExternalID1", Path: "Path", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, { ID: "UserID2", ExternalID: "ExternalID2", Path: "Path", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, }, groupID: "GroupID", @@ -962,6 +1026,7 @@ func TestPostgresRepo_GetGroupMembers(t *testing.T) { Path: "Path", Urn: "urn1", CreateAt: now, + UpdateAt: now, }, { ID: "UserID2", @@ -969,12 +1034,13 @@ func TestPostgresRepo_GetGroupMembers(t *testing.T) { Path: "Path", Urn: "urn2", CreateAt: now, + UpdateAt: now, }, }, }, "ErrorCase": { relations: &relations{ - users: []api.User{ + users: []User{ { ID: "UserID1", }, @@ -1003,8 +1069,7 @@ func TestPostgresRepo_GetGroupMembers(t *testing.T) { continue } if !test.relations.userNotFound { - if err := insertUser(user.ID, user.ExternalID, user.Path, - user.CreateAt.UnixNano(), user.Urn); err != nil { + if err := insertUser(user); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue } @@ -1215,7 +1280,7 @@ func TestPostgresRepo_IsAttachedToGroup(t *testing.T) { func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { type relations struct { - policies []api.Policy + policies []Policy groupID string policyNotFound bool } @@ -1233,13 +1298,14 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { }{ "OkCase": { relations: &relations{ - policies: []api.Policy{ + policies: []Policy{ { ID: "PolicyID1", Name: "Name1", Org: "org1", Path: "/path/", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: "Urn1", }, { @@ -1247,7 +1313,8 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { Name: "Name2", Org: "org1", Path: "/path/", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: "Urn2", }, }, @@ -1263,6 +1330,7 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: "Urn1", Statements: &[]api.Statement{}, }, @@ -1272,6 +1340,7 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: "Urn2", Statements: &[]api.Statement{}, }, @@ -1279,13 +1348,14 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { }, "ErrorCase": { relations: &relations{ - policies: []api.Policy{ + policies: []Policy{ { ID: "PolicyID1", Name: "Name1", Org: "org1", Path: "/path/", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: "Urn1", }, { @@ -1293,7 +1363,8 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { Name: "Name2", Org: "org1", Path: "/path/", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: "Urn2", }, }, @@ -1322,8 +1393,7 @@ func TestPostgresRepo_GetAttachedPolicies(t *testing.T) { continue } if !test.relations.policyNotFound { - if err := insertPolicy(policy.ID, policy.Name, policy.Org, policy.Path, - policy.CreateAt.UnixNano(), policy.Urn, test.statements); err != nil { + if err := insertPolicy(policy, test.statements); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue } diff --git a/database/postgresql/policy.go b/database/postgresql/policy.go index b416fc3..9498afd 100644 --- a/database/postgresql/policy.go +++ b/database/postgresql/policy.go @@ -19,6 +19,7 @@ func (p PostgresRepo) AddPolicy(policy api.Policy) (*api.Policy, error) { Name: policy.Name, Path: policy.Path, CreateAt: policy.CreateAt.UnixNano(), + UpdateAt: policy.UpdateAt.UnixNano(), Urn: policy.Urn, Org: policy.Org, } @@ -188,19 +189,14 @@ func (p PostgresRepo) GetPoliciesFiltered(org string, filter *api.Filter) ([]api return apiPolicies, total, nil } -func (p PostgresRepo) UpdatePolicy(policy api.Policy, name string, path string, urn string, statements []api.Statement) (*api.Policy, error) { - // Create policy to update - policyUpdated := Policy{ - Name: name, - Path: path, - Urn: urn, - } +func (p PostgresRepo) UpdatePolicy(policy api.Policy) (*api.Policy, error) { policyDB := Policy{ ID: policy.ID, Name: policy.Name, Path: policy.Path, CreateAt: policy.CreateAt.UTC().UnixNano(), + UpdateAt: policy.UpdateAt.UTC().UnixNano(), Urn: policy.Urn, Org: policy.Org, } @@ -208,7 +204,7 @@ func (p PostgresRepo) UpdatePolicy(policy api.Policy, name string, path string, transaction := p.Dbmap.Begin() // Update policy - if err := transaction.Model(&policyDB).Update(policyUpdated).Error; err != nil { + if err := transaction.Model(&Policy{ID: policy.ID}).Update(policyDB).Error; err != nil { transaction.Rollback() return nil, &database.Error{ Code: database.INTERNAL_ERROR, @@ -226,7 +222,7 @@ func (p PostgresRepo) UpdatePolicy(policy api.Policy, name string, path string, } // Create new statements - for _, s := range statements { + for _, s := range *policy.Statements { statementDB := &Statement{ ID: uuid.NewV4().String(), PolicyID: policy.ID, @@ -245,11 +241,7 @@ func (p PostgresRepo) UpdatePolicy(policy api.Policy, name string, path string, transaction.Commit() - // Create API policy - policyApi := dbPolicyToAPIPolicy(&policyDB) - policyApi.Statements = &statements - - return policyApi, nil + return &policy, nil } func (p PostgresRepo) RemovePolicy(id string) error { @@ -330,6 +322,7 @@ func dbPolicyToAPIPolicy(policydb *Policy) *api.Policy { Name: policydb.Name, Path: policydb.Path, CreateAt: time.Unix(0, policydb.CreateAt).UTC(), + UpdateAt: time.Unix(0, policydb.UpdateAt).UTC(), Urn: policydb.Urn, Org: policydb.Org, } diff --git a/database/postgresql/policy_test.go b/database/postgresql/policy_test.go index 5f7082e..41d9b19 100644 --- a/database/postgresql/policy_test.go +++ b/database/postgresql/policy_test.go @@ -12,7 +12,8 @@ import ( func TestPostgresRepo_AddPolicy(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { - previousPolicy *api.Policy + previousPolicy *Policy + statements []Statement policy api.Policy // Expected result expectedResponse *api.Policy @@ -25,6 +26,7 @@ func TestPostgresRepo_AddPolicy(t *testing.T) { Org: "123", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -44,6 +46,7 @@ func TestPostgresRepo_AddPolicy(t *testing.T) { Org: "123", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -59,23 +62,22 @@ func TestPostgresRepo_AddPolicy(t *testing.T) { }, }, "ErrorCaseAlreadyExists": { - previousPolicy: &api.Policy{ + previousPolicy: &Policy{ ID: "test1", Name: "test", Org: "123", Path: "/path/", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), - Statements: &[]api.Statement{ - { - Effect: "allow", - Actions: []string{ - api.USER_ACTION_GET_USER, - }, - Resources: []string{ - api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), - }, - }, + }, + statements: []Statement{ + { + ID: "test1", + PolicyID: "test1", + Effect: "allow", + Actions: api.USER_ACTION_GET_USER, + Resources: api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), }, }, policy: api.Policy{ @@ -111,7 +113,7 @@ func TestPostgresRepo_AddPolicy(t *testing.T) { // Call to repository to add a policy if test.previousPolicy != nil { - _, err := repoDB.AddPolicy(*test.previousPolicy) + err := insertPolicy(*test.previousPolicy, test.statements) if err != nil { t.Errorf("Test %v failed. Unexpected error: %v", n, err) continue @@ -189,6 +191,7 @@ func TestPostgresRepo_GetPolicyByName(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), }, statements: []Statement{ @@ -206,6 +209,7 @@ func TestPostgresRepo_GetPolicyByName(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -237,7 +241,7 @@ func TestPostgresRepo_GetPolicyByName(t *testing.T) { // Insert previous data if test.policy != nil { - err := insertPolicy(test.policy.ID, test.policy.Name, test.policy.Org, test.policy.Path, test.policy.CreateAt, test.policy.Urn, test.statements) + err := insertPolicy(*test.policy, test.statements) if err != nil { t.Errorf("Test %v failed. Error inserting policy/statements: %v", n, err) } @@ -287,6 +291,7 @@ func TestPostgresRepo_GetPolicyById(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), }, statements: []Statement{ @@ -304,6 +309,7 @@ func TestPostgresRepo_GetPolicyById(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -334,7 +340,7 @@ func TestPostgresRepo_GetPolicyById(t *testing.T) { // Insert previous data if test.policy != nil { - err := insertPolicy(test.policy.ID, test.policy.Name, test.policy.Org, test.policy.Path, test.policy.CreateAt, test.policy.Urn, test.statements) + err := insertPolicy(*test.policy, test.statements) if err != nil { t.Errorf("Test %v failed. Error inserting policy/statements: %v", n, err) } @@ -390,6 +396,7 @@ func TestPostgresRepo_GetPoliciesFiltered(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), }, statements: []Statement{ @@ -408,6 +415,7 @@ func TestPostgresRepo_GetPoliciesFiltered(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -441,7 +449,7 @@ func TestPostgresRepo_GetPoliciesFiltered(t *testing.T) { // Insert previous data if test.policy != nil { - err := insertPolicy(test.policy.ID, test.policy.Name, test.policy.Org, test.policy.Path, test.policy.CreateAt, test.policy.Urn, test.statements) + err := insertPolicy(*test.policy, test.statements) if err != nil { t.Errorf("Test %v failed. Error inserting policy/statements: %v", n, err) } @@ -470,10 +478,6 @@ func TestPostgresRepo_UpdatePolicy(t *testing.T) { testcases := map[string]struct { previousPolicy *api.Policy policy api.Policy - name string - path string - urn string - statements []api.Statement // Expected result expectedResponse *api.Policy }{ @@ -499,11 +503,11 @@ func TestPostgresRepo_UpdatePolicy(t *testing.T) { }, policy: api.Policy{ ID: "test1", - Name: "test", + Name: "newName", Org: "123", - Path: "/path/", + Path: "/newPath/", CreateAt: now, - Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), + Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/newPath/", "newName"), Statements: &[]api.Statement{ { Effect: "allow", @@ -511,25 +515,11 @@ func TestPostgresRepo_UpdatePolicy(t *testing.T) { api.USER_ACTION_GET_USER, }, Resources: []string{ - api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), + api.GetUrnPrefix("123", api.RESOURCE_USER, "/newPath/"), }, }, }, }, - name: "newName", - path: "/newPath/", - urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/newPath/", "newName"), - statements: []api.Statement{ - { - Effect: "allow", - Actions: []string{ - api.USER_ACTION_GET_USER, - }, - Resources: []string{ - api.GetUrnPrefix("123", api.RESOURCE_USER, "/newPath/"), - }, - }, - }, expectedResponse: &api.Policy{ ID: "test1", Name: "newName", @@ -565,7 +555,7 @@ func TestPostgresRepo_UpdatePolicy(t *testing.T) { continue } } - receivedPolicy, err := repoDB.UpdatePolicy(test.policy, test.name, test.path, test.urn, test.statements) + receivedPolicy, err := repoDB.UpdatePolicy(test.policy) if err != nil { t.Errorf("Test %v failed. Unexpected error: %v", n, err) continue @@ -579,41 +569,77 @@ func TestPostgresRepo_UpdatePolicy(t *testing.T) { } func TestPostgresRepo_RemovePolicy(t *testing.T) { + type relation struct { + policyID string + groupID string + groupNotFound bool + } + type policyData struct { + policy Policy + statements []Statement + } now := time.Now().UTC() testcases := map[string]struct { - previousPolicy *api.Policy - id string - group *api.Group + // Previous data + previousPolicies []policyData + relations []relation + // Postgres Repo Args + policyToDelete string }{ "OkCase": { - previousPolicy: &api.Policy{ - ID: "test1", - Name: "test", - Org: "123", - Path: "/path/", - CreateAt: now, - Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), - Statements: &[]api.Statement{ - { - Effect: "allow", - Actions: []string{ - api.USER_ACTION_GET_USER, + previousPolicies: []policyData{ + { + policy: Policy{ + ID: "test1", + Name: "test1", + Org: "123", + Path: "/path/", + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), + Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test1"), + }, + statements: []Statement{ + { + ID: "test1", + PolicyID: "test1", + Effect: "allow", + Actions: api.USER_ACTION_GET_USER, + Resources: api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), }, - Resources: []string{ - api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), + }, + }, + { + policy: Policy{ + ID: "test2", + Name: "test2", + Org: "123", + Path: "/path/", + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), + Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test2"), + }, + statements: []Statement{ + { + ID: "test2", + PolicyID: "test2", + Effect: "allow", + Actions: api.USER_ACTION_GET_USER, + Resources: api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), }, }, }, }, - id: "test1", - group: &api.Group{ - ID: "GroupID", - Name: "Name", - Path: "Path", - Urn: "urn", - CreateAt: now, - Org: "Org", + relations: []relation{ + { + policyID: "test1", + groupID: "GroupID", + }, + { + policyID: "test2", + groupID: "GroupID2", + }, }, + policyToDelete: "test1", }, } @@ -624,34 +650,32 @@ func TestPostgresRepo_RemovePolicy(t *testing.T) { cleanGroupTable() cleanGroupPolicyRelationTable() - // Call to repository to add a policy - if test.previousPolicy != nil { - _, err := repoDB.AddPolicy(*test.previousPolicy) - if err != nil { - t.Errorf("Test %v failed. Unexpected error: %v", n, err) - continue + // insert previous policy + if test.previousPolicies != nil { + for _, p := range test.previousPolicies { + err := insertPolicy(p.policy, p.statements) + if err != nil { + t.Errorf("Test %v failed. Unexpected error inserting previous policies: %v", n, err) + continue + } } } - if test.group != nil { - err := insertGroup(test.group.ID, test.group.Name, test.group.Path, - test.group.CreateAt.UnixNano(), test.group.Urn, test.group.Org) - if err != nil { - t.Errorf("Test %v failed. Unexpected error inserting group: %v", n, err) - continue - } - err = insertGroupPolicyRelation(test.group.ID, test.previousPolicy.ID) - if err != nil { - t.Errorf("Test %v failed. Unexpected error inserting group relation: %v", n, err) - continue + if test.relations != nil { + for _, rel := range test.relations { + err := insertGroupPolicyRelation(rel.groupID, rel.policyID) + if err != nil { + t.Errorf("Test %v failed. Unexpected error inserting group relation: %v", n, err) + continue + } } } - err := repoDB.RemovePolicy(test.id) + err := repoDB.RemovePolicy(test.policyToDelete) if err != nil { t.Errorf("Test %v failed. Unexpected error: %v", n, err) continue } // Check database - policyNumber, err := getPoliciesCountFiltered(test.id, "", "", "", 0, "") + policyNumber, err := getPoliciesCountFiltered(test.policyToDelete, "", "", "", 0, "") if err != nil { t.Errorf("Test %v failed. Unexpected error counting policies: %v", n, err) continue @@ -663,7 +687,7 @@ func TestPostgresRepo_RemovePolicy(t *testing.T) { statementNumber, err := getStatementsCountFiltered( "", - test.id, + test.policyToDelete, "", "", "") @@ -676,13 +700,34 @@ func TestPostgresRepo_RemovePolicy(t *testing.T) { continue } - groupPolicyRelationNumber, err := getGroupPolicyRelationCount(test.previousPolicy.ID, "") + // Check total policy number + totalPolicyNumber, err := getPoliciesCountFiltered("", "", "", "", 0, "") if err != nil { - t.Errorf("Test %v failed. Unexpected error counting relations: %v", n, err) + t.Errorf("Test %v failed. Unexpected error counting total policies: %v", n, err) continue } - if groupPolicyRelationNumber != 0 { - t.Errorf("Test %v failed. Received different relations number: %v", n, groupPolicyRelationNumber) + if totalPolicyNumber != 1 { + t.Errorf("Test %v failed. Received different total policy number: %v", n, totalPolicyNumber) + continue + } + + totalStatementNumber, err := getStatementsCountFiltered("", "", "", "", "") + if err != nil { + t.Errorf("Test %v failed. Unexpected error counting statements: %v", n, err) + continue + } + if totalStatementNumber != 1 { + t.Errorf("Test %v failed. Received different total statements number: %v", n, totalStatementNumber) + continue + } + + totalGroupPolicyRelationNumber, err := getGroupPolicyRelationCount("", "") + if err != nil { + t.Errorf("Test %v failed. Unexpected error counting total group policy relations: %v", n, err) + continue + } + if totalGroupPolicyRelationNumber != 1 { + t.Errorf("Test %v failed. Received different total relations group policy number: %v", n, totalGroupPolicyRelationNumber) continue } } @@ -691,38 +736,39 @@ func TestPostgresRepo_RemovePolicy(t *testing.T) { func TestPostgresRepo_GetAttachedGroups(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { - previousPolicy *api.Policy + previousPolicy *Policy + statements []Statement filter *api.Filter - group *api.Group + group *Group expectedResponse []api.Group }{ "OkCase": { - previousPolicy: &api.Policy{ + previousPolicy: &Policy{ ID: "test1", Name: "test", Org: "123", Path: "/path/", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), - Statements: &[]api.Statement{ - { - Effect: "allow", - Actions: []string{ - api.USER_ACTION_GET_USER, - }, - Resources: []string{ - api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), - }, - }, + }, + statements: []Statement{ + { + ID: "test1", + PolicyID: "test1", + Effect: "allow", + Actions: api.USER_ACTION_GET_USER, + Resources: api.GetUrnPrefix("", api.RESOURCE_USER, "/path/"), }, }, filter: testFilter, - group: &api.Group{ + group: &Group{ ID: "GroupID", Name: "Name", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, expectedResponse: []api.Group{ @@ -732,6 +778,7 @@ func TestPostgresRepo_GetAttachedGroups(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, Org: "Org", }, }, @@ -746,14 +793,13 @@ func TestPostgresRepo_GetAttachedGroups(t *testing.T) { cleanGroupPolicyRelationTable() // Call to repository to add a policy - _, err := repoDB.AddPolicy(*test.previousPolicy) + err := insertPolicy(*test.previousPolicy, test.statements) if err != nil { t.Errorf("Test %v failed. Unexpected error: %v", n, err) continue } if test.group != nil { - err := insertGroup(test.group.ID, test.group.Name, test.group.Path, - test.group.CreateAt.UnixNano(), test.group.Urn, test.group.Org) + err := insertGroup(*test.group) if err != nil { t.Errorf("Test %v failed. Unexpected error inserting group: %v", n, err) continue @@ -796,6 +842,7 @@ func Test_dbPolicyToAPIPolicy(t *testing.T) { Org: "123", Path: "/path/", CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), }, apiPolicy: &api.Policy{ @@ -804,6 +851,7 @@ func Test_dbPolicyToAPIPolicy(t *testing.T) { Org: "123", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("123", api.RESOURCE_POLICY, "/path/", "test"), }, }, diff --git a/database/postgresql/postgres_db.go b/database/postgresql/postgres_db.go index f280ca5..12fcbf1 100644 --- a/database/postgresql/postgres_db.go +++ b/database/postgresql/postgres_db.go @@ -43,16 +43,12 @@ func InitDb(datasourcename string, idleConns string, maxOpenConns string, connTT return nil, err } - // Create tables if not exist = + // Create tables if not exist err = db.AutoMigrate(&User{}, &Group{}, &Policy{}, &Statement{}, &GroupUserRelation{}, &GroupPolicyRelation{}).Error if err != nil { return nil, err } - // TODO: - // Activate sql logger - //db.LogMode(true) - return db, nil } @@ -62,6 +58,7 @@ type User struct { ExternalID string `gorm:"not null;unique"` Path string `gorm:"not null"` CreateAt int64 `gorm:"not null"` + UpdateAt int64 `gorm:"not null"` Urn string `gorm:"not null;unique"` } @@ -77,6 +74,7 @@ type Group struct { Path string `gorm:"not null"` Org string `gorm:"not null"` CreateAt int64 `gorm:"not null"` + UpdateAt int64 `gorm:"not null"` Urn string `gorm:"not null;unique"` } @@ -92,6 +90,7 @@ type Policy struct { Path string `gorm:"not null"` Org string `gorm:"not null"` CreateAt int64 `gorm:"not null"` + UpdateAt int64 `gorm:"not null"` Urn string `gorm:"not null;unique"` } diff --git a/database/postgresql/postgres_db_test.go b/database/postgresql/postgres_db_test.go index 637aeb8..0612da2 100644 --- a/database/postgresql/postgres_db_test.go +++ b/database/postgresql/postgres_db_test.go @@ -78,9 +78,9 @@ func TestInitDb(t *testing.T) { // Aux methods -func insertUser(id string, externalID string, path string, createAt int64, urn string) error { - err := repoDB.Dbmap.Exec("INSERT INTO public.users (id, external_id, path, create_at, urn) VALUES (?, ?, ?, ?, ?)", - id, externalID, path, createAt, urn).Error +func insertUser(user User) error { + err := repoDB.Dbmap.Exec("INSERT INTO public.users (id, external_id, path, create_at, update_at, urn) VALUES (?, ?, ?, ?, ?, ?)", + user.ID, user.ExternalID, user.Path, user.CreateAt, user.UpdateAt, user.Urn).Error // Error handling if err != nil { @@ -106,7 +106,7 @@ func insertGroupUserRelation(userID string, groupID string) error { return nil } -func getUsersCountFiltered(id string, externalID string, path string, createAt int64, urn string, pathPrefix string) (int, error) { +func getUsersCountFiltered(id string, externalID string, path string, createAt int64, updateAt int64, urn string, pathPrefix string) (int, error) { query := repoDB.Dbmap.Table(User{}.TableName()) if id != "" { query = query.Where("id = ?", id) @@ -123,6 +123,9 @@ func getUsersCountFiltered(id string, externalID string, path string, createAt i if createAt != 0 { query = query.Where("create_at = ?", createAt) } + if updateAt != 0 { + query = query.Where("update_at = ?", updateAt) + } if urn != "" { query = query.Where("urn = ?", urn) } @@ -150,9 +153,9 @@ func cleanGroupUserRelationTable() error { // GROUP -func insertGroup(id string, name string, path string, createAt int64, urn string, org string) error { - err := repoDB.Dbmap.Exec("INSERT INTO public.groups (id, name, path, create_at, urn, org) VALUES (?, ?, ?, ?, ?, ?)", - id, name, path, createAt, urn, org).Error +func insertGroup(group Group) error { + err := repoDB.Dbmap.Exec("INSERT INTO public.groups (id, name, path, create_at, update_at, urn, org) VALUES (?, ?, ?, ?, ?, ?, ?)", + group.ID, group.Name, group.Path, group.CreateAt, group.UpdateAt, group.Urn, group.Org).Error // Error handling if err != nil { @@ -164,7 +167,7 @@ func insertGroup(id string, name string, path string, createAt int64, urn string return nil } -func getGroupsCountFiltered(id string, name string, path string, createAt int64, urn string, org string) (int, error) { +func getGroupsCountFiltered(id string, name string, path string, createAt int64, updateAt int64, urn string, org string) (int, error) { query := repoDB.Dbmap.Table(Group{}.TableName()) if id != "" { query = query.Where("id = ?", id) @@ -178,6 +181,9 @@ func getGroupsCountFiltered(id string, name string, path string, createAt int64, if createAt != 0 { query = query.Where("create_at = ?", createAt) } + if updateAt != 0 { + query = query.Where("update_at = ?", updateAt) + } if urn != "" { query = query.Where("urn = ?", urn) } @@ -239,9 +245,9 @@ func cleanStatementTable() error { return nil } -func insertPolicy(id string, name string, org string, path string, createAt int64, urn string, statements []Statement) error { - err := repoDB.Dbmap.Exec("INSERT INTO public.policies (id, name, org, path, create_at, urn) VALUES (?, ?, ?, ?, ?, ?)", - id, name, org, path, createAt, urn).Error +func insertPolicy(policy Policy, statements []Statement) error { + err := repoDB.Dbmap.Exec("INSERT INTO public.policies (id, name, org, path, create_at, update_at, urn) VALUES (?, ?, ?, ?, ?, ?, ?)", + policy.ID, policy.Name, policy.Org, policy.Path, policy.CreateAt, policy.UpdateAt, policy.Urn).Error // Error handling if err != nil { @@ -252,7 +258,8 @@ func insertPolicy(id string, name string, org string, path string, createAt int6 } for _, v := range statements { - err = insertStatements(v.ID, v.PolicyID, v.Actions, v.Effect, v.Resources) + v.PolicyID = policy.ID + err = insertStatements(v) // Error handling if err != nil { return &database.Error{ @@ -265,9 +272,9 @@ func insertPolicy(id string, name string, org string, path string, createAt int6 return nil } -func insertStatements(id string, policyId string, actions string, effect string, resources string) error { +func insertStatements(statement Statement) error { err := repoDB.Dbmap.Exec("INSERT INTO public.statements (id, policy_id, effect, actions, resources) VALUES (?, ?, ?, ?, ?)", - id, policyId, effect, actions, resources).Error + statement.ID, statement.PolicyID, statement.Effect, statement.Actions, statement.Resources).Error // Error handling if err != nil { diff --git a/database/postgresql/user.go b/database/postgresql/user.go index a0ee8a5..8cfbdc6 100644 --- a/database/postgresql/user.go +++ b/database/postgresql/user.go @@ -18,6 +18,7 @@ func (u PostgresRepo) AddUser(user api.User) (*api.User, error) { ExternalID: user.ExternalID, Path: user.Path, CreateAt: user.CreateAt.UnixNano(), + UpdateAt: user.UpdateAt.UnixNano(), Urn: user.Urn, } @@ -111,24 +112,19 @@ func (u PostgresRepo) GetUsersFiltered(filter *api.Filter) ([]api.User, int, err return apiusers, total, nil } -func (u PostgresRepo) UpdateUser(user api.User, newPath string, newUrn string) (*api.User, error) { - - // Create new user - userUpdated := User{ - Path: newPath, - Urn: newUrn, - } +func (u PostgresRepo) UpdateUser(user api.User) (*api.User, error) { userDB := User{ ID: user.ID, ExternalID: user.ExternalID, Path: user.Path, CreateAt: user.CreateAt.UnixNano(), + UpdateAt: user.UpdateAt.UnixNano(), Urn: user.Urn, } // Update user - query := u.Dbmap.Model(&userDB).Update(userUpdated) + query := u.Dbmap.Model(&User{ID: user.ID}).Updates(userDB) // Error Handling if err := query.Error; err != nil { @@ -138,7 +134,7 @@ func (u PostgresRepo) UpdateUser(user api.User, newPath string, newUrn string) ( } } - return dbUserToAPIUser(&userDB), nil + return &user, nil } func (u PostgresRepo) RemoveUser(id string) error { @@ -213,6 +209,7 @@ func dbUserToAPIUser(userdb *User) *api.User { ExternalID: userdb.ExternalID, Path: userdb.Path, CreateAt: time.Unix(0, userdb.CreateAt).UTC(), + UpdateAt: time.Unix(0, userdb.UpdateAt).UTC(), Urn: userdb.Urn, } } diff --git a/database/postgresql/user_test.go b/database/postgresql/user_test.go index 0b23908..a7ce063 100644 --- a/database/postgresql/user_test.go +++ b/database/postgresql/user_test.go @@ -13,7 +13,7 @@ func TestPostgresRepo_AddUser(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousUser *api.User + previousUser *User // Postgres Repo Args userToCreate *api.User // Expected result @@ -27,6 +27,7 @@ func TestPostgresRepo_AddUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, expectedResponse: &api.User{ ID: "UserID", @@ -34,15 +35,17 @@ func TestPostgresRepo_AddUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseUserAlreadyExist": { - previousUser: &api.User{ + previousUser: &User{ ID: "UserID", ExternalID: "ExternalID", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, userToCreate: &api.User{ ID: "UserID", @@ -50,6 +53,7 @@ func TestPostgresRepo_AddUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, expectedError: &database.Error{ Code: database.INTERNAL_ERROR, @@ -64,8 +68,7 @@ func TestPostgresRepo_AddUser(t *testing.T) { // Insert previous data if test.previousUser != nil { - if err := insertUser(test.previousUser.ID, test.previousUser.ExternalID, test.previousUser.Path, - test.previousUser.CreateAt.Unix(), test.previousUser.Urn); err != nil { + if err := insertUser(*test.previousUser); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) continue } @@ -94,7 +97,7 @@ func TestPostgresRepo_AddUser(t *testing.T) { } // Check database userNumber, err := getUsersCountFiltered(test.expectedResponse.ID, test.expectedResponse.ExternalID, test.expectedResponse.Path, - test.expectedResponse.CreateAt.UnixNano(), test.expectedResponse.Urn, "") + test.expectedResponse.CreateAt.UnixNano(), test.expectedResponse.UpdateAt.UnixNano(), test.expectedResponse.Urn, "") if err != nil { t.Errorf("Test %v failed. Unexpected error counting users: %v", n, err) continue @@ -113,7 +116,7 @@ func TestPostgresRepo_GetUserByExternalID(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousUser *api.User + previousUser *User // Postgres Repo Args externalID string // Expected result @@ -121,12 +124,13 @@ func TestPostgresRepo_GetUserByExternalID(t *testing.T) { expectedError *database.Error }{ "OkCase": { - previousUser: &api.User{ + previousUser: &User{ ID: "UserID", ExternalID: "ExternalID", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, externalID: "ExternalID", expectedResponse: &api.User{ @@ -135,15 +139,17 @@ func TestPostgresRepo_GetUserByExternalID(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseUserNotExist": { - previousUser: &api.User{ + previousUser: &User{ ID: "UserID", ExternalID: "ExternalID", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, externalID: "NotExist", expectedError: &database.Error{ @@ -159,8 +165,7 @@ func TestPostgresRepo_GetUserByExternalID(t *testing.T) { // Insert previous data if test.previousUser != nil { - if err := insertUser(test.previousUser.ID, test.previousUser.ExternalID, test.previousUser.Path, - test.previousUser.CreateAt.UnixNano(), test.previousUser.Urn); err != nil { + if err := insertUser(*test.previousUser); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) continue } @@ -196,7 +201,7 @@ func TestPostgresRepo_GetUserByID(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousUser *api.User + previousUser *User // Postgres Repo Args userID string // Expected result @@ -204,12 +209,13 @@ func TestPostgresRepo_GetUserByID(t *testing.T) { expectedError *database.Error }{ "OkCase": { - previousUser: &api.User{ + previousUser: &User{ ID: "UserID", ExternalID: "ExternalID", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, userID: "UserID", expectedResponse: &api.User{ @@ -218,15 +224,17 @@ func TestPostgresRepo_GetUserByID(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseUserNotExist": { - previousUser: &api.User{ + previousUser: &User{ ID: "UserID", ExternalID: "ExternalID", Path: "Path", Urn: "urn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, userID: "NotExist", expectedError: &database.Error{ @@ -242,8 +250,7 @@ func TestPostgresRepo_GetUserByID(t *testing.T) { // Insert previous data if test.previousUser != nil { - if err := insertUser(test.previousUser.ID, test.previousUser.ExternalID, test.previousUser.Path, - test.previousUser.CreateAt.UnixNano(), test.previousUser.Urn); err != nil { + if err := insertUser(*test.previousUser); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) continue } @@ -280,27 +287,29 @@ func TestPostgresRepo_GetUsersFiltered(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousUsers []api.User + previousUsers []User // Postgres Repo Args filter *api.Filter // Expected result expectedResponse []api.User }{ "OkCase1": { - previousUsers: []api.User{ + previousUsers: []User{ { ID: "UserID1", ExternalID: "ExternalID1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, { ID: "UserID2", ExternalID: "ExternalID2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, }, filter: &api.Filter{ @@ -315,6 +324,7 @@ func TestPostgresRepo_GetUsersFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, }, { ID: "UserID2", @@ -322,24 +332,27 @@ func TestPostgresRepo_GetUsersFiltered(t *testing.T) { Path: "Path456", Urn: "urn2", CreateAt: now, + UpdateAt: now, }, }, }, "OkCase2": { - previousUsers: []api.User{ + previousUsers: []User{ { ID: "UserID1", ExternalID: "ExternalID1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, { ID: "UserID2", ExternalID: "ExternalID2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, }, filter: &api.Filter{ @@ -354,24 +367,27 @@ func TestPostgresRepo_GetUsersFiltered(t *testing.T) { Path: "Path123", Urn: "urn1", CreateAt: now, + UpdateAt: now, }, }, }, "OkCase3": { - previousUsers: []api.User{ + previousUsers: []User{ { ID: "UserID1", ExternalID: "ExternalID1", Path: "Path123", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, { ID: "UserID2", ExternalID: "ExternalID2", Path: "Path456", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, }, filter: &api.Filter{ @@ -390,8 +406,7 @@ func TestPostgresRepo_GetUsersFiltered(t *testing.T) { // Insert previous data if test.previousUsers != nil { for _, previousUser := range test.previousUsers { - if err := insertUser(previousUser.ID, previousUser.ExternalID, previousUser.Path, - previousUser.CreateAt.UnixNano(), previousUser.Urn); err != nil { + if err := insertUser(previousUser); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) continue } @@ -421,37 +436,36 @@ func TestPostgresRepo_UpdateUser(t *testing.T) { now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousUser *api.User + previousUser *User // Postgres Repo Args userToUpdate *api.User - newPath string - newUrn string // Expected result expectedResponse *api.User }{ "OkCase": { - previousUser: &api.User{ + previousUser: &User{ ID: "UserID", ExternalID: "ExternalID", Path: "OldPath", Urn: "Oldurn", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), }, userToUpdate: &api.User{ ID: "UserID", ExternalID: "ExternalID", - Path: "OldPath", - Urn: "Oldurn", + Path: "NewPath", + Urn: "NewUrn", CreateAt: now, + UpdateAt: now, }, - newPath: "NewPath", - newUrn: "NewUrn", expectedResponse: &api.User{ ID: "UserID", ExternalID: "ExternalID", Path: "NewPath", Urn: "NewUrn", CreateAt: now, + UpdateAt: now, }, }, } @@ -462,14 +476,13 @@ func TestPostgresRepo_UpdateUser(t *testing.T) { // Insert previous data if test.previousUser != nil { - if err := insertUser(test.previousUser.ID, test.previousUser.ExternalID, test.previousUser.Path, - test.previousUser.CreateAt.UnixNano(), test.previousUser.Urn); err != nil { + if err := insertUser(*test.previousUser); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) continue } } // Call to repository to update an user - updatedUser, err := repoDB.UpdateUser(*test.userToUpdate, test.newPath, test.newUrn) + updatedUser, err := repoDB.UpdateUser(*test.userToUpdate) if err != nil { t.Errorf("Test %v failed. Unexpected error: %v", n, err) @@ -482,7 +495,7 @@ func TestPostgresRepo_UpdateUser(t *testing.T) { } // Check database userNumber, err := getUsersCountFiltered(test.expectedResponse.ID, test.expectedResponse.ExternalID, test.expectedResponse.Path, - test.expectedResponse.CreateAt.UnixNano(), test.expectedResponse.Urn, "") + test.expectedResponse.CreateAt.UnixNano(), test.expectedResponse.UpdateAt.UnixNano(), test.expectedResponse.Urn, "") if err != nil { t.Errorf("Test %v failed. Unexpected error counting users: %v", n, err) continue @@ -498,28 +511,45 @@ func TestPostgresRepo_UpdateUser(t *testing.T) { func TestPostgresRepo_RemoveUser(t *testing.T) { type relation struct { userID string - groupIDs []string + groupID string groupNotFound bool } now := time.Now().UTC() testcases := map[string]struct { // Previous data - previousUser *api.User - relation *relation + previousUsers []User + relations []relation // Postgres Repo Args userToDelete string }{ "OkCase": { - previousUser: &api.User{ - ID: "UserID", - ExternalID: "ExternalID", - Path: "OldPath", - Urn: "Oldurn", - CreateAt: now, + previousUsers: []User{ + { + ID: "UserID", + ExternalID: "ExternalID", + Path: "OldPath", + Urn: "Oldurn", + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), + }, + { + ID: "UserID2", + ExternalID: "ExternalID2", + Path: "OldPath", + Urn: "Oldurn2", + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), + }, }, - relation: &relation{ - userID: "UserID", - groupIDs: []string{"GroupID1", "GroupID2"}, + relations: []relation{ + { + userID: "UserID", + groupID: "GroupID", + }, + { + userID: "UserID2", + groupID: "GroupID", + }, }, userToDelete: "UserID", }, @@ -531,16 +561,17 @@ func TestPostgresRepo_RemoveUser(t *testing.T) { cleanGroupUserRelationTable() // Insert previous data - if test.previousUser != nil { - if err := insertUser(test.previousUser.ID, test.previousUser.ExternalID, test.previousUser.Path, - test.previousUser.CreateAt.Unix(), test.previousUser.Urn); err != nil { - t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) - continue + if test.previousUsers != nil { + for _, usr := range test.previousUsers { + if err := insertUser(usr); err != nil { + t.Errorf("Test %v failed. Unexpected error inserting previous users: %v", n, err) + continue + } } } - if test.relation != nil { - for _, id := range test.relation.groupIDs { - if err := insertGroupUserRelation(test.relation.userID, id); err != nil { + if test.relations != nil { + for _, rel := range test.relations { + if err := insertGroupUserRelation(rel.userID, rel.groupID); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous group user relations: %v", n, err) continue } @@ -550,8 +581,7 @@ func TestPostgresRepo_RemoveUser(t *testing.T) { err := repoDB.RemoveUser(test.userToDelete) // Check database - userNumber, err := getUsersCountFiltered(test.userToDelete, "", "", - 0, "", "") + userNumber, err := getUsersCountFiltered(test.userToDelete, "", "", 0, 0, "", "") if err != nil { t.Errorf("Test %v failed. Unexpected error counting users: %v", n, err) continue @@ -561,13 +591,36 @@ func TestPostgresRepo_RemoveUser(t *testing.T) { continue } - relations, err := getGroupUserRelations("", test.previousUser.ID) + // Check total users + totalUserNumber, err := getUsersCountFiltered("", "", "", 0, 0, "", "") + if err != nil { + t.Errorf("Test %v failed. Unexpected error counting total users: %v", n, err) + continue + } + if totalUserNumber != 1 { + t.Errorf("Test %v failed. Received different total user number: %v", n, totalUserNumber) + continue + } + + // Check user deleted relations + relations, err := getGroupUserRelations("", test.userToDelete) if err != nil { - t.Errorf("Test %v failed. Unexpected error counting relations: %v", n, err) + t.Errorf("Test %v failed. Unexpected error counting group user relations: %v", n, err) continue } if relations != 0 { - t.Errorf("Test %v failed. Received different relations number: %v", n, relations) + t.Errorf("Test %v failed. Received different group user relation number: %v", n, relations) + continue + } + + // Check total user relations + totalRelations, err := getGroupUserRelations("", "") + if err != nil { + t.Errorf("Test %v failed. Unexpected error counting total group user relations: %v", n, err) + continue + } + if totalRelations != 1 { + t.Errorf("Test %v failed. Received different total group user relation number: %v", n, totalRelations) continue } @@ -577,7 +630,7 @@ func TestPostgresRepo_RemoveUser(t *testing.T) { func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { type relation struct { userID string - groups []api.Group + groups []Group groupNotFound bool } now := time.Now().UTC() @@ -594,13 +647,14 @@ func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { "OkCase": { relation: &relation{ userID: "UserID", - groups: []api.Group{ + groups: []Group{ { ID: "GroupID1", Name: "Name1", Path: "Path1", Urn: "urn1", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, { @@ -608,7 +662,8 @@ func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { Name: "Name2", Path: "Path2", Urn: "urn2", - CreateAt: now, + CreateAt: now.UnixNano(), + UpdateAt: now.UnixNano(), Org: "Org", }, }, @@ -622,6 +677,7 @@ func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { Path: "Path1", Urn: "urn1", CreateAt: now, + UpdateAt: now, Org: "Org", }, { @@ -630,6 +686,7 @@ func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { Path: "Path2", Urn: "urn2", CreateAt: now, + UpdateAt: now, Org: "Org", }, }, @@ -637,7 +694,7 @@ func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { "ErrorCase": { relation: &relation{ userID: "UserID", - groups: []api.Group{ + groups: []Group{ { ID: "GroupID1", }, @@ -670,8 +727,7 @@ func TestPostgresRepo_GetGroupsByUserID(t *testing.T) { continue } if !test.relation.groupNotFound { - if err := insertGroup(group.ID, group.Name, group.Path, - group.CreateAt.UnixNano(), group.Urn, group.Org); err != nil { + if err := insertGroup(group); err != nil { t.Errorf("Test %v failed. Unexpected error inserting previous data: %v", n, err) continue } diff --git a/http/group_test.go b/http/group_test.go index 5990fdb..de80a70 100644 --- a/http/group_test.go +++ b/http/group_test.go @@ -43,6 +43,7 @@ func TestWorkerHandler_HandleAddGroup(t *testing.T) { Urn: "Urn", Org: "org1", CreateAt: now, + UpdateAt: now, }, addGroupResult: &api.Group{ ID: "GroupID", @@ -51,6 +52,7 @@ func TestWorkerHandler_HandleAddGroup(t *testing.T) { Urn: "Urn", Org: "org1", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseMalformedRequest": { @@ -234,6 +236,7 @@ func TestWorkerHandler_HandleGetGroupByName(t *testing.T) { Urn: "Urn", Org: "Org", CreateAt: now, + UpdateAt: now, }, getGroupByNameResult: &api.Group{ ID: "groupID", @@ -242,6 +245,7 @@ func TestWorkerHandler_HandleGetGroupByName(t *testing.T) { Urn: "Urn", Org: "Org", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseGroupNotFound": { @@ -733,6 +737,7 @@ func TestWorkerHandler_HandleUpdateGroup(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, updateGroupResult: &api.Group{ ID: "GroupID", @@ -740,6 +745,7 @@ func TestWorkerHandler_HandleUpdateGroup(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseMalformedRequest": { diff --git a/http/policy_test.go b/http/policy_test.go index 6fa4ac6..af5b368 100644 --- a/http/policy_test.go +++ b/http/policy_test.go @@ -51,6 +51,7 @@ func TestWorkerHandler_HandleAddPolicy(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -70,6 +71,7 @@ func TestWorkerHandler_HandleAddPolicy(t *testing.T) { Name: "test", Org: "org1", CreateAt: now, + UpdateAt: now, Path: "/path/", Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ @@ -310,6 +312,7 @@ func TestWorkerHandler_HandleGetPolicy(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -329,6 +332,7 @@ func TestWorkerHandler_HandleGetPolicy(t *testing.T) { Org: "org1", Path: "/path/", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -862,6 +866,7 @@ func TestWorkerHandler_HandleUpdatePolicy(t *testing.T) { Path: "/path/", Org: "org1", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { @@ -881,6 +886,7 @@ func TestWorkerHandler_HandleUpdatePolicy(t *testing.T) { Path: "/path/", Org: "org1", CreateAt: now, + UpdateAt: now, Urn: api.CreateUrn("org1", api.RESOURCE_POLICY, "/path/", "test"), Statements: &[]api.Statement{ { diff --git a/http/proxy_test.go b/http/proxy_test.go index 931b6b9..6d29cd4 100644 --- a/http/proxy_test.go +++ b/http/proxy_test.go @@ -37,6 +37,7 @@ func TestProxyHandler_HandleRequest(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, getUserByExternalIdResult: &api.User{ ID: "UserID", @@ -44,6 +45,7 @@ func TestProxyHandler_HandleRequest(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, getAuthorizedExternalResourcesResult: []string{"urn:ews:example:instance1:resource/user"}, }, diff --git a/http/user_test.go b/http/user_test.go index 6fcf10f..969d3a1 100644 --- a/http/user_test.go +++ b/http/user_test.go @@ -40,6 +40,7 @@ func TestWorkerHandler_HandleAddUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, addUserResult: &api.User{ ID: "UserID", @@ -47,6 +48,7 @@ func TestWorkerHandler_HandleAddUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseMalformedRequest": { @@ -221,6 +223,7 @@ func TestWorkerHandler_HandleGetUserByExternalID(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, getUserByExternalIdResult: &api.User{ ID: "UserID", @@ -228,6 +231,7 @@ func TestWorkerHandler_HandleGetUserByExternalID(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseUserNotExist": { @@ -522,6 +526,7 @@ func TestWorkerHandler_HandleUpdateUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, updateUserResult: &api.User{ ID: "UserID", @@ -529,6 +534,7 @@ func TestWorkerHandler_HandleUpdateUser(t *testing.T) { Path: "Path", Urn: "urn", CreateAt: now, + UpdateAt: now, }, }, "ErrorCaseMalformedRequest": { diff --git a/scripts/database/postgres/0.2.0/downgrade.sql b/scripts/database/postgres/0.2.0/downgrade.sql new file mode 100644 index 0000000..1c5d8cd --- /dev/null +++ b/scripts/database/postgres/0.2.0/downgrade.sql @@ -0,0 +1,50 @@ +DO $$ + DECLARE COL_EXIST NUMERIC(10); + BEGIN + ------------------------ + -- ALTER TABLE groups -- + ------------------------ + -- Add the updateAt column + SELECT COUNT(column_name) INTO COL_EXIST + FROM information_schema.columns + WHERE table_name LIKE 'groups' AND column_name LIKE 'update_at'; + + IF COL_EXIST = 1 THEN + EXECUTE 'ALTER TABLE groups DROP COLUMN update_at'; + RAISE NOTICE '[INFO] Alter table groups to remove next column: update_at'; + ELSE + RAISE NOTICE '[WARN] The groups column could not be removed. Check if this column exists'; + END IF; + + ------------------------ + -- ALTER TABLE users -- + ------------------------ + -- Add the updateAt column + SELECT COUNT(column_name) INTO COL_EXIST + FROM information_schema.columns + WHERE table_name LIKE 'users' AND column_name LIKE 'update_at'; + + IF COL_EXIST = 1 THEN + EXECUTE 'ALTER TABLE users DROP COLUMN update_at'; + RAISE NOTICE '[INFO] Alter table users to remove next column: update_at'; + ELSE + RAISE NOTICE '[WARN] The users column could not be removed. Check if this column exists'; + END IF; + + ------------------------ + -- ALTER TABLE policies -- + ------------------------ + -- Add the updateAt column + SELECT COUNT(column_name) INTO COL_EXIST + FROM information_schema.columns + WHERE table_name LIKE 'policies' AND column_name LIKE 'update_at'; + + IF COL_EXIST = 1 THEN + EXECUTE 'ALTER TABLE policies DROP COLUMN update_at'; + RAISE NOTICE '[INFO] Alter table policies to remove next column: update_at'; + ELSE + RAISE NOTICE '[WARN] The policies column could not be removed. Check if this column exists'; + END IF; + + END $$ +; \ No newline at end of file diff --git a/scripts/database/postgres/0.2.0/upgrade.sql b/scripts/database/postgres/0.2.0/upgrade.sql new file mode 100644 index 0000000..42e97ca --- /dev/null +++ b/scripts/database/postgres/0.2.0/upgrade.sql @@ -0,0 +1,56 @@ +DO $$ + DECLARE COL_EXIST NUMERIC(10); + BEGIN + ------------------------ + -- ALTER TABLE groups -- + ------------------------ + -- Add the updateAt column + SELECT COUNT(column_name) INTO COL_EXIST + FROM information_schema.columns + WHERE table_name LIKE 'groups' AND column_name LIKE 'update_at'; + + IF COL_EXIST = 0 THEN + EXECUTE 'ALTER TABLE groups ADD update_at BIGINT'; + EXECUTE 'UPDATE groups SET update_at = create_at'; + EXECUTE 'ALTER TABLE groups ALTER COLUMN update_at SET NOT NULL'; + RAISE NOTICE '[INFO] Alter table groups to add next column: update_at'; + ELSE + RAISE NOTICE '[WARN] The groups column could not be created. Check if this column already exists'; + END IF; + + ------------------------ + -- ALTER TABLE users -- + ------------------------ + -- Add the updateAt column + SELECT COUNT(column_name) INTO COL_EXIST + FROM information_schema.columns + WHERE table_name LIKE 'users' AND column_name LIKE 'update_at'; + + IF COL_EXIST = 0 THEN + EXECUTE 'ALTER TABLE users ADD update_at BIGINT'; + EXECUTE 'UPDATE users SET update_at = create_at'; + EXECUTE 'ALTER TABLE users ALTER COLUMN update_at SET NOT NULL'; + RAISE NOTICE '[INFO] Alter table users to add next column: update_at'; + ELSE + RAISE NOTICE '[WARN] The users column could not be created. Check if this column already exists'; + END IF; + + ------------------------ + -- ALTER TABLE policies -- + ------------------------ + -- Add the updateAt column + SELECT COUNT(column_name) INTO COL_EXIST + FROM information_schema.columns + WHERE table_name LIKE 'policies' AND column_name LIKE 'update_at'; + + IF COL_EXIST = 0 THEN + EXECUTE 'ALTER TABLE policies ADD update_at BIGINT'; + EXECUTE 'UPDATE policies SET update_at = create_at'; + EXECUTE 'ALTER TABLE policies ALTER COLUMN update_at SET NOT NULL'; + RAISE NOTICE '[INFO] Alter table policies to add next column: update_at'; + ELSE + RAISE NOTICE '[WARN] The policies column could not be created. Check if this column already exists'; + END IF; + + END $$ +; \ No newline at end of file