storj/pkg/satellite/satellitedb/projectmembers.go
Yehor Butko e82edc68c8
V3-976 Create db query for filtering team mebers (#940)
* V3-976 Create db query for filtering team mebers

* fixing linter

* fixing linter

* sql injection fixed

* getOrder renamed, tests added
2018-12-28 14:07:35 +02:00

173 lines
4.8 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
"context"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/zeebo/errs"
"storj.io/storj/pkg/satellite"
"storj.io/storj/pkg/satellite/satellitedb/dbx"
"storj.io/storj/pkg/utils"
)
// ProjectMembers exposes methods to manage ProjectMembers table in database.
type projectMembers struct {
methods dbx.Methods
db *dbx.DB
}
// GetByMemberID is a method for querying project member from the database by memberID.
func (pm *projectMembers) GetByMemberID(ctx context.Context, memberID uuid.UUID) ([]satellite.ProjectMember, error) {
projectMembersDbx, err := pm.methods.All_ProjectMember_By_MemberId(ctx, dbx.ProjectMember_MemberId(memberID[:]))
if err != nil {
return nil, err
}
return projectMembersFromDbxSlice(projectMembersDbx)
}
// GetByProjectID is a method for querying project members from the database by projectID, offset and limit.
func (pm *projectMembers) GetByProjectID(ctx context.Context, projectID uuid.UUID, pagination satellite.Pagination) ([]satellite.ProjectMember, error) {
if pagination.Limit < 0 || pagination.Offset < 0 {
return nil, errs.New("invalid pagination argument")
}
var projectMembers []satellite.ProjectMember
searchSubQuery := "%" + pagination.Search + "%"
//`+getOrder(pagination.Order)+`
rebindedQuery := 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.first_name LIKE ? OR
u.last_name LIKE ? )
ORDER BY ` + sanitizedOrderColumnName(pagination.Order) + ` ASC
LIMIT ? OFFSET ?
`)
rows, err := pm.db.Query(rebindedQuery, projectID[:], searchSubQuery, searchSubQuery, searchSubQuery, pagination.Limit, pagination.Offset)
defer func() {
err = errs.Combine(err, rows.Close())
}()
if err != nil {
return nil, err
}
for rows.Next() {
pm := satellite.ProjectMember{}
var memberIDBytes, projectIDBytes []uint8
var memberID, projectID uuid.UUID
scanErr := rows.Scan(&memberIDBytes, &projectIDBytes, &pm.CreatedAt)
if err != nil {
err = errs.Combine(err, scanErr)
continue
}
memberID, convertErr := bytesToUUID(memberIDBytes)
if convertErr != nil {
err = errs.Combine(err, convertErr)
continue
}
projectID, convertErr = bytesToUUID(projectIDBytes)
if convertErr != nil {
err = errs.Combine(err, convertErr)
continue
}
pm.ProjectID = projectID
pm.MemberID = memberID
projectMembers = append(projectMembers, pm)
}
return projectMembers, err
}
// Insert is a method for inserting project member into the database.
func (pm *projectMembers) Insert(ctx context.Context, memberID, projectID uuid.UUID) (*satellite.ProjectMember, error) {
createdProjectMember, err := pm.methods.Create_ProjectMember(ctx,
dbx.ProjectMember_MemberId(memberID[:]),
dbx.ProjectMember_ProjectId(projectID[:]))
if err != nil {
return nil, err
}
return projectMemberFromDBX(createdProjectMember)
}
// Delete is a method for deleting project member by memberID and projectID from the database.
func (pm *projectMembers) Delete(ctx context.Context, memberID, projectID uuid.UUID) error {
_, err := pm.methods.Delete_ProjectMember_By_MemberId_And_ProjectId(
ctx,
dbx.ProjectMember_MemberId(memberID[:]),
dbx.ProjectMember_ProjectId(projectID[:]),
)
return err
}
// projectMemberFromDBX is used for creating ProjectMember entity from autogenerated dbx.ProjectMember struct
func projectMemberFromDBX(projectMember *dbx.ProjectMember) (*satellite.ProjectMember, error) {
if projectMember == nil {
return nil, errs.New("projectMember parameter is nil")
}
memberID, err := bytesToUUID(projectMember.MemberId)
if err != nil {
return nil, err
}
projectID, err := bytesToUUID(projectMember.ProjectId)
if err != nil {
return nil, err
}
return &satellite.ProjectMember{
MemberID: memberID,
ProjectID: projectID,
CreatedAt: projectMember.CreatedAt,
}, nil
}
// sanitizedOrderColumnName return valid order by column
func sanitizedOrderColumnName(pmo satellite.ProjectMemberOrder) string {
switch pmo {
case 2:
return "u.email"
case 3:
return "u.created_at"
default:
return "u.first_name"
}
}
// projectMembersFromDbxSlice is used for creating []ProjectMember entities from autogenerated []*dbx.ProjectMember struct
func projectMembersFromDbxSlice(projectMembersDbx []*dbx.ProjectMember) ([]satellite.ProjectMember, error) {
var projectMembers []satellite.ProjectMember
var errors []error
// Generating []dbo from []dbx and collecting all errors
for _, projectMemberDbx := range projectMembersDbx {
projectMember, err := projectMemberFromDBX(projectMemberDbx)
if err != nil {
errors = append(errors, err)
continue
}
projectMembers = append(projectMembers, *projectMember)
}
return projectMembers, utils.CombineErrors(errors...)
}