satellite/{console,satellitedb}: clean up obsolete project member code

This change removes the obsolete project member paging code.
Previously, we implemented functionality for including project
invitations in pages of project members. However, the satellite
frontend still expected API responses to use the old paging style, so
the related code could not be removed right away. Now that the frontend
has been updated, this code is no longer necessary.

References #5855

Change-Id: I12fdaaeb869977c4d87a0d50b9a7b11c68552c82
This commit is contained in:
Jeremy Wharton 2023-06-08 03:49:53 -05:00 committed by Storj Robot
parent 8ee7d104a0
commit 6b65b7e7d0
12 changed files with 108 additions and 303 deletions

View File

@ -319,7 +319,7 @@ func TestGraphqlMutation(t *testing.T) {
data := result.(map[string]interface{})
proj := data[consoleql.AddProjectMembersMutation].(map[string]interface{})
members := proj[consoleql.FieldMembers].(map[string]interface{})
members := proj[consoleql.FieldMembersAndInvitations].(map[string]interface{})
projectMembers := members[consoleql.FieldProjectMembers].([]interface{})
assert.Equal(t, project.ID.String(), proj[consoleql.FieldID])
@ -330,7 +330,7 @@ func TestGraphqlMutation(t *testing.T) {
t.Run("Add project members mutation", func(t *testing.T) {
query := fmt.Sprintf(
"mutation {addProjectMembers(projectID:\"%s\",email:[\"%s\",\"%s\"]){id,publicId,name,members(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
"mutation {addProjectMembers(projectID:\"%s\",email:[\"%s\",\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
project.ID.String(),
user1.Email,
user2.Email,
@ -341,7 +341,7 @@ func TestGraphqlMutation(t *testing.T) {
t.Run("Add project members mutation with publicId", func(t *testing.T) {
query := fmt.Sprintf(
"mutation {addProjectMembers(publicId:\"%s\",email:[\"%s\"]){id,publicId,name,members(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
"mutation {addProjectMembers(publicId:\"%s\",email:[\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
project.PublicID.String(),
user3.Email,
)
@ -351,7 +351,7 @@ func TestGraphqlMutation(t *testing.T) {
t.Run("Fail add project members mutation without ID", func(t *testing.T) {
query := fmt.Sprintf(
"mutation {addProjectMembers(email:[\"%s\",\"%s\"]){id,publicId,name,members(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
"mutation {addProjectMembers(email:[\"%s\",\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
user1.Email,
user2.Email,
)
@ -362,7 +362,7 @@ func TestGraphqlMutation(t *testing.T) {
t.Run("Delete project members mutation", func(t *testing.T) {
query := fmt.Sprintf(
"mutation {deleteProjectMembers(projectID:\"%s\",email:[\"%s\",\"%s\",\"%s\"]){id,publicId,name,members(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{user{id}}}}}",
"mutation {deleteProjectMembers(projectID:\"%s\",email:[\"%s\",\"%s\",\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{user{id}}}}}",
project.ID.String(),
user1.Email,
user2.Email,
@ -375,7 +375,7 @@ func TestGraphqlMutation(t *testing.T) {
data := result.(map[string]interface{})
proj := data[consoleql.DeleteProjectMembersMutation].(map[string]interface{})
members := proj[consoleql.FieldMembers].(map[string]interface{})
members := proj[consoleql.FieldMembersAndInvitations].(map[string]interface{})
projectMembers := members[consoleql.FieldProjectMembers].([]interface{})
rootMember := projectMembers[0].(map[string]interface{})[consoleql.UserType].(map[string]interface{})

View File

@ -34,8 +34,6 @@ const (
BucketUsageType = "bucketUsage"
// BucketUsagePageType is a graphql type name for bucket usage page.
BucketUsagePageType = "bucketUsagePage"
// ProjectMembersPageType is a graphql type name for project members page.
ProjectMembersPageType = "projectMembersPage"
// ProjectMembersAndInvitationsPageType is a graphql type name for a page of project members and invitations.
ProjectMembersAndInvitationsPageType = "projectMembersAndInvitationsPage"
// ProjectMembersCursorInputType is a graphql type name for project members.
@ -54,8 +52,6 @@ const (
FieldBucketName = "bucketName"
// FieldDescription is a field name for description.
FieldDescription = "description"
// FieldMembers is field name for members.
FieldMembers = "members"
// FieldMembersAndInvitations is field name for members and invitations.
FieldMembersAndInvitations = "membersAndInvitations"
// FieldAPIKeys is a field name for api keys.
@ -112,48 +108,6 @@ const (
// graphqlProject creates *graphql.Object type representation of satellite.ProjectInfo.
func graphqlProject(service *console.Service, types *TypeCreator) *graphql.Object {
resolveMembersAndInvites := func(p graphql.ResolveParams, pagingType console.ProjectMembersPagingType) (interface{}, error) {
project, _ := p.Source.(*console.Project)
_, err := console.GetUser(p.Context)
if err != nil {
return nil, err
}
cursor := cursorArgsToProjectMembersCursor(p.Args[CursorArg].(map[string]interface{}))
page, err := service.GetProjectMembers(p.Context, project.ID, cursor, pagingType)
if err != nil {
return nil, err
}
var users []projectMember
for _, member := range page.ProjectMembers {
user, err := service.GetUser(p.Context, member.MemberID)
if err != nil {
return nil, err
}
users = append(users, projectMember{
User: user,
JoinedAt: member.CreatedAt,
})
}
projectMembersPage := projectMembersPage{
ProjectMembers: users,
ProjectInvitations: page.ProjectInvitations,
TotalCount: page.TotalCount,
Offset: page.Offset,
Limit: page.Limit,
Order: int(page.Order),
OrderDirection: int(page.OrderDirection),
Search: page.Search,
CurrentPage: page.CurrentPage,
PageCount: page.PageCount,
}
return projectMembersPage, nil
}
return graphql.NewObject(graphql.ObjectConfig{
Name: ProjectType,
Fields: graphql.Fields{
@ -178,18 +132,6 @@ func graphqlProject(service *console.Service, types *TypeCreator) *graphql.Objec
FieldMemberCount: &graphql.Field{
Type: graphql.Int,
},
// TODO: Remove once the frontend has been updated to select membersAndInvitations.
FieldMembers: &graphql.Field{
Type: types.projectMemberPage,
Args: graphql.FieldConfigArgument{
CursorArg: &graphql.ArgumentConfig{
Type: graphql.NewNonNull(types.projectMembersCursor),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return resolveMembersAndInvites(p, console.Members)
},
},
FieldMembersAndInvitations: &graphql.Field{
Type: types.projectMembersAndInvitationsPage,
Args: graphql.FieldConfigArgument{
@ -198,7 +140,45 @@ func graphqlProject(service *console.Service, types *TypeCreator) *graphql.Objec
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return resolveMembersAndInvites(p, console.MembersAndInvitations)
project, _ := p.Source.(*console.Project)
_, err := console.GetUser(p.Context)
if err != nil {
return nil, err
}
cursor := cursorArgsToProjectMembersCursor(p.Args[CursorArg].(map[string]interface{}))
page, err := service.GetProjectMembersAndInvitations(p.Context, project.ID, cursor)
if err != nil {
return nil, err
}
var users []projectMember
for _, member := range page.ProjectMembers {
user, err := service.GetUser(p.Context, member.MemberID)
if err != nil {
return nil, err
}
users = append(users, projectMember{
User: user,
JoinedAt: member.CreatedAt,
})
}
projectMembersPage := projectMembersPage{
ProjectMembers: users,
ProjectInvitations: page.ProjectInvitations,
TotalCount: page.TotalCount,
Offset: page.Offset,
Limit: page.Limit,
Order: int(page.Order),
OrderDirection: int(page.OrderDirection),
Search: page.Search,
CurrentPage: page.CurrentPage,
PageCount: page.PageCount,
}
return projectMembersPage, nil
},
},
FieldAPIKeys: &graphql.Field{

View File

@ -78,68 +78,44 @@ func graphqlProjectMembersCursor() *graphql.InputObject {
})
}
func graphqlProjectMembersPage(types *TypeCreator) *graphql.Object {
fields := graphql.Fields{
FieldProjectMembers: &graphql.Field{
Type: graphql.NewList(types.projectMember),
},
}
for k, v := range commonProjectMembersPageFields() {
fields[k] = v
}
return graphql.NewObject(graphql.ObjectConfig{
Name: ProjectMembersPageType,
Fields: fields,
})
}
func graphqlProjectMembersAndInvitationsPage(types *TypeCreator) *graphql.Object {
fields := graphql.Fields{
FieldProjectMembers: &graphql.Field{
Type: graphql.NewList(types.projectMember),
},
FieldProjectInvitations: &graphql.Field{
Type: graphql.NewList(types.projectInvitation),
},
}
for k, v := range commonProjectMembersPageFields() {
fields[k] = v
}
return graphql.NewObject(graphql.ObjectConfig{
Name: ProjectMembersAndInvitationsPageType,
Fields: fields,
Name: ProjectMembersAndInvitationsPageType,
Fields: graphql.Fields{
FieldProjectMembers: &graphql.Field{
Type: graphql.NewList(types.projectMember),
},
FieldProjectInvitations: &graphql.Field{
Type: graphql.NewList(types.projectInvitation),
},
SearchArg: &graphql.Field{
Type: graphql.String,
},
LimitArg: &graphql.Field{
Type: graphql.Int,
},
OrderArg: &graphql.Field{
Type: graphql.Int,
},
OrderDirectionArg: &graphql.Field{
Type: graphql.Int,
},
OffsetArg: &graphql.Field{
Type: graphql.Int,
},
FieldPageCount: &graphql.Field{
Type: graphql.Int,
},
FieldCurrentPage: &graphql.Field{
Type: graphql.Int,
},
FieldTotalCount: &graphql.Field{
Type: graphql.Int,
},
},
})
}
func commonProjectMembersPageFields() graphql.Fields {
return graphql.Fields{
SearchArg: &graphql.Field{
Type: graphql.String,
},
LimitArg: &graphql.Field{
Type: graphql.Int,
},
OrderArg: &graphql.Field{
Type: graphql.Int,
},
OrderDirectionArg: &graphql.Field{
Type: graphql.Int,
},
OffsetArg: &graphql.Field{
Type: graphql.Int,
},
FieldPageCount: &graphql.Field{
Type: graphql.Int,
},
FieldCurrentPage: &graphql.Field{
Type: graphql.Int,
},
FieldTotalCount: &graphql.Field{
Type: graphql.Int,
},
}
}
// projectMember encapsulates User and joinedAt.
type projectMember struct {
User *console.User

View File

@ -286,7 +286,7 @@ func TestGraphqlQuery(t *testing.T) {
t.Run("Project query team members", func(t *testing.T) {
query := fmt.Sprintf(
"query {project(id: \"%s\") {members( cursor: { limit: %d, search: \"%s\", page: %d, order: %d, orderDirection: %d } ) { projectMembers{ user { id, fullName, shortName, email, createdAt }, joinedAt }, search, limit, order, offset, pageCount, currentPage, totalCount } } }",
"query {project(id: \"%s\") {membersAndInvitations( cursor: { limit: %d, search: \"%s\", page: %d, order: %d, orderDirection: %d } ) { projectMembers{ user { id, fullName, shortName, email, createdAt }, joinedAt }, search, limit, order, offset, pageCount, currentPage, totalCount } } }",
createdProject.ID.String(),
5,
"",
@ -298,7 +298,7 @@ func TestGraphqlQuery(t *testing.T) {
data := result.(map[string]interface{})
project := data[consoleql.ProjectQuery].(map[string]interface{})
members := project[consoleql.FieldMembers].(map[string]interface{})
members := project[consoleql.FieldMembersAndInvitations].(map[string]interface{})
projectMembers := members[consoleql.FieldProjectMembers].([]interface{})
assert.Equal(t, 3, len(projectMembers))

View File

@ -25,7 +25,6 @@ type TypeCreator struct {
bucketUsagePage *graphql.Object
projectMember *graphql.Object
projectInvitation *graphql.Object
projectMemberPage *graphql.Object
projectMembersAndInvitationsPage *graphql.Object
apiKeyPage *graphql.Object
apiKeyInfo *graphql.Object
@ -119,11 +118,6 @@ func (c *TypeCreator) Create(log *zap.Logger, service *console.Service, mailServ
return err
}
c.projectMemberPage = graphqlProjectMembersPage(c)
if err := c.projectMemberPage.Error(); err != nil {
return err
}
c.projectMembersAndInvitationsPage = graphqlProjectMembersAndInvitationsPage(c)
if err := c.projectMembersAndInvitationsPage.Error(); err != nil {
return err

View File

@ -575,7 +575,7 @@ func TestProjects(t *testing.T) {
"query": `
query ($projectId: String!, $limit: Int!, $search: String!, $page: Int!, $order: Int!, $orderDirection: Int!) {
project(id: $projectId) {
members(cursor: {limit: $limit, search: $search, page: $page, order: $order, orderDirection: $orderDirection}) {
membersAndInvitations(cursor: {limit: $limit, search: $search, page: $page, order: $order, orderDirection: $orderDirection}) {
projectMembers {
user {
id
@ -598,7 +598,7 @@ func TestProjects(t *testing.T) {
__typename
}
}`}))
require.Contains(t, body, "projectMembersPage")
require.Contains(t, body, "projectMembersAndInvitationsPage")
require.Equal(t, http.StatusOK, resp.StatusCode)
}
@ -787,7 +787,7 @@ func TestWrongUser(t *testing.T) {
"query": `
query ($projectId: String!, $limit: Int!, $search: String!, $page: Int!, $order: Int!, $orderDirection: Int!) {
project(id: $projectId) {
members(cursor: {limit: $limit, search: $search, page: $page, order: $order, orderDirection: $orderDirection}) {
membersAndInvitations(cursor: {limit: $limit, search: $search, page: $page, order: $order, orderDirection: $orderDirection}) {
projectMembers {
user {
id

View File

@ -16,9 +16,6 @@ import (
type ProjectMembers interface {
// GetByMemberID is a method for querying project members from the database by memberID.
GetByMemberID(ctx context.Context, memberID uuid.UUID) ([]ProjectMember, error)
// GetPagedByProjectID is a method for querying project members from the database by projectID and cursor.
// TODO: Remove once all uses have been replaced by GetPagedWithInvitationsByProjectID.
GetPagedByProjectID(ctx context.Context, projectID uuid.UUID, cursor ProjectMembersCursor) (*ProjectMembersPage, error)
// GetPagedWithInvitationsByProjectID is a method for querying project members and invitations from the database by projectID and cursor.
GetPagedWithInvitationsByProjectID(ctx context.Context, projectID uuid.UUID, cursor ProjectMembersCursor) (*ProjectMembersPage, error)
// Insert is a method for inserting project member into the database.
@ -62,18 +59,6 @@ type ProjectMembersPage struct {
TotalCount uint64
}
// ProjectMembersPagingType determines what types of results should be returned
// in a project members page.
type ProjectMembersPagingType int
const (
// Members indicates that only project members should be returned in a project members page.
Members ProjectMembersPagingType = iota
// MembersAndInvitations indicates that project members and project invitations should be
// returned in a project members page.
MembersAndInvitations
)
// ProjectMemberOrder is used for querying project members in specified order.
type ProjectMemberOrder int8

View File

@ -80,7 +80,7 @@ func TestProjectMembersRepository(t *testing.T) {
t.Run("Get paged", func(t *testing.T) {
// sql injection test. F.E '%SomeText%' = > ''%SomeText%' OR 'x' != '%'' will be true
members, err := projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 6, Search: "son%' OR 'x' != '", Order: 2, Page: 1})
members, err := projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 6, Search: "son%' OR 'x' != '", Order: 2, Page: 1})
assert.NoError(t, err)
assert.NotNil(t, members)
assert.Equal(t, uint64(0), members.TotalCount)
@ -88,7 +88,7 @@ func TestProjectMembersRepository(t *testing.T) {
assert.Equal(t, uint(0), members.PageCount)
assert.Equal(t, 0, len(members.ProjectMembers))
members, err = projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 3, Search: "", Order: 1, Page: 1})
members, err = projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 3, Search: "", Order: 1, Page: 1})
assert.NoError(t, err)
assert.NotNil(t, members)
assert.Equal(t, uint64(5), members.TotalCount)
@ -96,25 +96,25 @@ func TestProjectMembersRepository(t *testing.T) {
assert.Equal(t, uint(2), members.PageCount)
assert.Equal(t, 3, len(members.ProjectMembers))
members, err = projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 2, Search: "iam", Order: 2, Page: 1}) // TODO: fix case sensitity issues and change back to "Liam"
members, err = projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 2, Search: "iam", Order: 2, Page: 1}) // TODO: fix case sensitity issues and change back to "Liam"
assert.NoError(t, err)
assert.NotNil(t, members)
assert.Equal(t, uint64(2), members.TotalCount)
assert.Equal(t, 2, len(members.ProjectMembers))
members, err = projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 2, Search: "iam", Order: 1, Page: 1}) // TODO: fix case sensitity issues and change back to "Liam"
members, err = projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 2, Search: "iam", Order: 1, Page: 1}) // TODO: fix case sensitity issues and change back to "Liam"
assert.NoError(t, err)
assert.NotNil(t, members)
assert.Equal(t, uint64(2), members.TotalCount)
assert.Equal(t, 2, len(members.ProjectMembers))
members, err = projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 6, Search: "son", Order: 123, Page: 1})
members, err = projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 6, Search: "son", Order: 123, Page: 1})
assert.NoError(t, err)
assert.NotNil(t, members)
assert.Equal(t, uint64(5), members.TotalCount)
assert.Equal(t, 5, len(members.ProjectMembers))
members, err = projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 6, Search: "son", Order: 2, Page: 1})
members, err = projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{Limit: 6, Search: "son", Order: 2, Page: 1})
assert.NoError(t, err)
assert.NotNil(t, members)
assert.Equal(t, uint64(5), members.TotalCount)
@ -141,7 +141,7 @@ func TestProjectMembersRepository(t *testing.T) {
err := projectMembers.Delete(ctx, createdUsers[0].ID, createdProjects[0].ID)
assert.NoError(t, err)
projMembers, err := projectMembers.GetPagedByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{
projMembers, err := projectMembers.GetPagedWithInvitationsByProjectID(ctx, createdProjects[0].ID, console.ProjectMembersCursor{
Order: 1,
Search: "",
Limit: 100,

View File

@ -2118,8 +2118,8 @@ func (s *Service) DeleteProjectMembersAndInvitations(ctx context.Context, projec
return Error.Wrap(err)
}
// GetProjectMembers returns ProjectMembers for given Project.
func (s *Service) GetProjectMembers(ctx context.Context, projectID uuid.UUID, cursor ProjectMembersCursor, pagingType ProjectMembersPagingType) (pmp *ProjectMembersPage, err error) {
// GetProjectMembersAndInvitations returns the project members and invitations for a given project.
func (s *Service) GetProjectMembersAndInvitations(ctx context.Context, projectID uuid.UUID, cursor ProjectMembersCursor) (pmp *ProjectMembersPage, err error) {
defer mon.Task()(&ctx)(&err)
user, err := s.getUserAndAuditLog(ctx, "get project members", zap.String("projectID", projectID.String()))
@ -2136,11 +2136,7 @@ func (s *Service) GetProjectMembers(ctx context.Context, projectID uuid.UUID, cu
cursor.Limit = maxLimit
}
if pagingType == MembersAndInvitations {
pmp, err = s.store.ProjectMembers().GetPagedWithInvitationsByProjectID(ctx, projectID, cursor)
} else {
pmp, err = s.store.ProjectMembers().GetPagedByProjectID(ctx, projectID, cursor)
}
pmp, err = s.store.ProjectMembers().GetPagedWithInvitationsByProjectID(ctx, projectID, cursor)
if err != nil {
return nil, Error.Wrap(err)
}

View File

@ -287,19 +287,19 @@ func TestService(t *testing.T) {
require.Nil(t, addedUsers)
})
t.Run("GetProjectMembers", func(t *testing.T) {
t.Run("GetProjectMembersAndInvitations", func(t *testing.T) {
// Getting the project members of an own project that one is a part of should work
userPage, err := service.GetProjectMembers(userCtx1, up1Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10}, console.Members)
userPage, err := service.GetProjectMembersAndInvitations(userCtx1, up1Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
require.NoError(t, err)
require.Len(t, userPage.ProjectMembers, 2)
// Getting the project members of a foreign project that one is a part of should work
userPage, err = service.GetProjectMembers(userCtx2, up1Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10}, console.Members)
userPage, err = service.GetProjectMembersAndInvitations(userCtx2, up1Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
require.NoError(t, err)
require.Len(t, userPage.ProjectMembers, 2)
// Getting the project members of a foreign project that one is not a part of should not work
userPage, err = service.GetProjectMembers(userCtx1, up2Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10}, console.Members)
userPage, err = service.GetProjectMembersAndInvitations(userCtx1, up2Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
require.Error(t, err)
require.Nil(t, userPage)
})

View File

@ -79,8 +79,7 @@ func (keys *apikeys) GetPagedByProjectID(ctx context.Context, projectID uuid.UUI
WHERE ak.project_id = ?
AND ak.project_id = p.id
AND lower(ak.name) LIKE ?
ORDER BY ` + sanitizedAPIKeyOrderColumnName(cursor.Order) + `
` + sanitizeOrderDirectionName(page.OrderDirection) + `
` + apikeySortClause(cursor.Order, page.OrderDirection) + `
LIMIT ? OFFSET ?`)
rows, err := keys.db.QueryContext(ctx,
@ -171,8 +170,7 @@ func (keys *apikeys) GetAllNamesByProjectID(ctx context.Context, projectID uuid.
SELECT ak.name
FROM api_keys ak
WHERE ak.project_id = ?
ORDER BY ` + sanitizedAPIKeyOrderColumnName(console.KeyName) + `
` + sanitizeOrderDirectionName(console.Ascending),
` + apikeySortClause(console.KeyName, console.Ascending),
)
rows, err := keys.db.QueryContext(ctx, query, projectID[:])
@ -285,11 +283,15 @@ func fromDBXAPIKey(ctx context.Context, row *dbx.ApiKey_Project_PublicId_Row) (_
return result, nil
}
// sanitizedAPIKeyOrderColumnName return valid order by column.
func sanitizedAPIKeyOrderColumnName(pmo console.APIKeyOrder) string {
if pmo == 2 {
return "ak.created_at"
// apikeySortClause returns what ORDER BY clause should be used when sorting API key results.
func apikeySortClause(order console.APIKeyOrder, direction console.OrderDirection) string {
dirStr := "ASC"
if direction == console.Descending {
dirStr = "DESC"
}
return "lower(ak.name)"
if order == console.CreationDate {
return "ORDER BY ak.created_at " + dirStr + ", ak.name, ak.project_id"
}
return "ORDER BY LOWER(ak.name) " + dirStr + ", ak.name, ak.project_id"
}

View File

@ -35,114 +35,6 @@ func (pm *projectMembers) GetByMemberID(ctx context.Context, memberID uuid.UUID)
return projectMembersFromDbxSlice(ctx, projectMembersDbx)
}
// GetByProjectID is a method for querying project members from the database by projectID, offset and limit.
// TODO: Remove once all uses have been replaced by GetPagedWithInvitationsByProjectID.
func (pm *projectMembers) GetPagedByProjectID(ctx context.Context, projectID uuid.UUID, cursor console.ProjectMembersCursor) (_ *console.ProjectMembersPage, err error) {
defer mon.Task()(&ctx)(&err)
search := "%" + strings.ReplaceAll(cursor.Search, " ", "%") + "%"
if cursor.Limit > 50 {
cursor.Limit = 50
}
if cursor.Page == 0 {
return nil, errs.New("page cannot be 0")
}
page := &console.ProjectMembersPage{
Search: cursor.Search,
Limit: cursor.Limit,
Offset: uint64((cursor.Page - 1) * cursor.Limit),
Order: cursor.Order,
OrderDirection: cursor.OrderDirection,
}
countQuery := pm.db.Rebind(`
SELECT COUNT(*)
FROM project_members pm
INNER JOIN users u ON pm.member_id = u.id
WHERE pm.project_id = ?
AND ( u.email LIKE ? OR
u.full_name LIKE ? OR
u.short_name LIKE ?
)`)
countRow := pm.db.QueryRowContext(ctx,
countQuery,
projectID[:],
search,
search,
search)
err = countRow.Scan(&page.TotalCount)
if err != nil {
return nil, err
}
if page.TotalCount == 0 {
return page, nil
}
if page.Offset > page.TotalCount-1 {
return nil, errs.New("page is out of range")
}
// TODO: LIKE is case-sensitive postgres, however this should be case-insensitive and possibly allow typos
reboundQuery := pm.db.Rebind(`
SELECT pm.*
FROM project_members pm
INNER JOIN users u ON pm.member_id = u.id
WHERE pm.project_id = ?
AND ( u.email LIKE ? OR
u.full_name LIKE ? OR
u.short_name LIKE ? )
ORDER BY ` + sanitizedOrderColumnName(cursor.Order) + `
` + sanitizeOrderDirectionName(page.OrderDirection) + `
LIMIT ? OFFSET ?`)
rows, err := pm.db.QueryContext(ctx,
reboundQuery,
projectID[:],
search,
search,
search,
page.Limit,
page.Offset)
defer func() {
err = errs.Combine(err, rows.Close())
}()
if err != nil {
return nil, err
}
var projectMembers []console.ProjectMember
for rows.Next() {
pm := console.ProjectMember{}
err = rows.Scan(&pm.MemberID, &pm.ProjectID, &pm.CreatedAt)
if err != nil {
return nil, err
}
projectMembers = append(projectMembers, pm)
}
if err := rows.Err(); err != nil {
return nil, err
}
page.ProjectMembers = projectMembers
page.Order = cursor.Order
page.PageCount = uint(page.TotalCount / uint64(cursor.Limit))
if page.TotalCount%uint64(cursor.Limit) != 0 {
page.PageCount++
}
page.CurrentPage = cursor.Page
return page, err
}
// GetPagedWithInvitationsByProjectID is a method for querying project members and invitations from the database by projectID, offset and limit.
func (pm *projectMembers) GetPagedWithInvitationsByProjectID(ctx context.Context, projectID uuid.UUID, cursor console.ProjectMembersCursor) (_ *console.ProjectMembersPage, err error) {
defer mon.Task()(&ctx)(&err)
@ -341,26 +233,6 @@ func projectMemberFromDBX(ctx context.Context, projectMember *dbx.ProjectMember)
}, nil
}
// sanitizedOrderColumnName return valid order by column.
func sanitizedOrderColumnName(pmo console.ProjectMemberOrder) string {
switch pmo {
case 2:
return "u.email"
case 3:
return "pm.created_at"
default:
return "u.full_name"
}
}
func sanitizeOrderDirectionName(pmo console.OrderDirection) string {
if pmo == 2 {
return "DESC"
}
return "ASC"
}
// projectMembersSortClause returns what ORDER BY clause should be used when sorting project member results.
func projectMembersSortClause(order console.ProjectMemberOrder, direction console.OrderDirection) string {
dirStr := "ASC"