Skip to content

Commit

Permalink
enhance filter handling in the sql share drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Sep 28, 2021
1 parent 89dcba4 commit 65d8cfc
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 30 deletions.
117 changes: 106 additions & 11 deletions pkg/cbox/share/sql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ import (
_ "github.com/go-sql-driver/mysql"
)

const (
shareTypeUser = 0
shareTypeGroup = 1
)

func init() {
registry.Register("sql", New)
}
Expand Down Expand Up @@ -276,19 +281,30 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference

func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
query := `SELECT coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with,
coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, id, stime, permissions, share_type
query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with,
coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, id, stime, permissions, share_type
FROM oc_share
WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner=? or uid_initiator=?) AND (share_type=? OR share_type=?)`
params := []interface{}{uid, uid, 0, 1}
for _, f := range filters {
if f.Type == collaboration.Filter_TYPE_RESOURCE_ID {
query += " AND (fileid_prefix=? AND item_source=?)"
params = append(params, f.GetResourceId().StorageId, f.GetResourceId().OpaqueId)
} else if f.Type == collaboration.Filter_TYPE_EXCLUDE_DENIALS {
// TODO this may change once the mapping of permission to share types is completed (cf. pkg/cbox/utils/conversions.go)
query += " AND (permissions > 0)"
WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner=? or uid_initiator=?)`
params := []interface{}{uid, uid}
var (
filterQuery string
filterParams []interface{}
err error
)
if len(filters) == 0 {
filterQuery += "(share_type=? OR share_type=?)"
params = append(params, shareTypeUser)
params = append(params, shareTypeGroup)
} else {
filterQuery, filterParams, err = translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)
}

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}

rows, err := m.db.Query(query, params...)
Expand Down Expand Up @@ -342,6 +358,16 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
}
}

filterQuery, filterParams, err := translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}

rows, err := m.db.Query(query, params...)
if err != nil {
return nil, err
Expand Down Expand Up @@ -476,3 +502,72 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, ref *collaboration.ShareR
rs.State = f.GetState()
return rs, nil
}

func groupFiltersByType(filters []*collaboration.Filter) map[collaboration.Filter_Type][]*collaboration.Filter {
grouped := make(map[collaboration.Filter_Type][]*collaboration.Filter)
for _, f := range filters {
grouped[f.Type] = append(grouped[f.Type], f)
}
return grouped
}

func granteeTypeToShareType(granteeType provider.GranteeType) int {
switch granteeType {
case provider.GranteeType_GRANTEE_TYPE_USER:
return shareTypeUser
case provider.GranteeType_GRANTEE_TYPE_GROUP:
return shareTypeGroup
}
return -1
}

// translateFilters translates the filters to sql queries
func translateFilters(filters []*collaboration.Filter) (string, []interface{}, error) {
var (
filterQuery string
params []interface{}
)

groupedFilters := groupFiltersByType(filters)
// If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator.
// That is why the filters got grouped by type.
// For every given filter type, iterate over the filters and if there are more than one combine them.
// Combine the different filter types using `AND`
var filterCounter = 0
for filterType, filters := range groupedFilters {
switch filterType {
case collaboration.Filter_TYPE_RESOURCE_ID:
filterQuery += "("
for i, f := range filters {
filterQuery += "item_source=?"
params = append(params, f.GetResourceId().OpaqueId)

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
case collaboration.Filter_TYPE_GRANTEE_TYPE:
filterQuery += "("
for i, f := range filters {
filterQuery += "share_type=?"
params = append(params, granteeTypeToShareType(f.GetGranteeType()))

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
case collaboration.Filter_TYPE_EXCLUDE_DENIALS:
// TODO this may change once the mapping of permission to share types is completed (cf. pkg/cbox/utils/conversions.go)
filterQuery += "permissions > 0"
default:
return "", nil, fmt.Errorf("filter type is not supported")
}
if filterCounter != len(groupedFilters)-1 {
filterQuery += " AND "
}
filterCounter++
}
return filterQuery, params, nil
}
11 changes: 8 additions & 3 deletions pkg/share/manager/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,17 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
continue
}

allFiltersMatch := true
for _, f := range filters {
if share.MatchesFilter(s, f) {
rs := m.convert(ctx, s)
rss = append(rss, rs)
if !share.MatchesFilter(s, f) {
allFiltersMatch = false
break
}
}
if allFiltersMatch {
rs := m.convert(ctx, s)
rss = append(rss, rs)
}
}
return rss, nil
}
Expand Down
12 changes: 8 additions & 4 deletions pkg/share/manager/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,17 @@ func (m *manager) ListReceivedShares(ctx context.Context, filters []*collaborati
rss = append(rss, rs)
continue
}

allFiltersMatch := true
for _, f := range filters {
if share.MatchesFilter(s, f) {
rs := m.convert(ctx, s)
rss = append(rss, rs)
if !share.MatchesFilter(s, f) {
allFiltersMatch = false
break
}
}
if allFiltersMatch {
rs := m.convert(ctx, s)
rss = append(rss, rs)
}
}
return rss, nil
}
Expand Down
114 changes: 102 additions & 12 deletions pkg/share/manager/sql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ import (
_ "github.com/go-sql-driver/mysql"
)

const (
shareTypeUser = 0
shareTypeGroup = 1
)

func init() {
registry.Register("oc10-sql", NewMysql)
}
Expand Down Expand Up @@ -271,20 +276,26 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference

func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
uid := ctxpkg.ContextMustGetUser(ctx).Username
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(item_source, '') as item_source, id, stime, permissions, share_type FROM oc_share WHERE (uid_owner=? or uid_initiator=?) AND (share_type=? OR share_type=?)"
var filterQuery string
params := []interface{}{uid, uid, 0, 1}
for i, f := range filters {
if f.Type == collaboration.Filter_TYPE_RESOURCE_ID {
filterQuery += "(item_source=?)"
if i != len(filters)-1 {
filterQuery += " AND "
}
params = append(params, f.GetResourceId().OpaqueId)
} else {
return nil, fmt.Errorf("filter type is not supported")
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(item_source, '') as item_source, id, stime, permissions, share_type FROM oc_share WHERE (uid_owner=? or uid_initiator=?)"
params := []interface{}{uid, uid}

var (
filterQuery string
filterParams []interface{}
err error
)
if len(filters) == 0 {
filterQuery += "(share_type=? OR share_type=?)"
params = append(params, shareTypeUser)
params = append(params, shareTypeGroup)
} else {
filterQuery, filterParams, err = translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)
}

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}
Expand Down Expand Up @@ -337,6 +348,16 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
query += "AND (share_with=?)"
}

filterQuery, filterParams, err := translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}

rows, err := m.db.Query(query, params...)
if err != nil {
return nil, err
Expand Down Expand Up @@ -500,3 +521,72 @@ func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey)
}
return m.convertToCS3ReceivedShare(ctx, s, m.storageMountID)
}

func groupFiltersByType(filters []*collaboration.Filter) map[collaboration.Filter_Type][]*collaboration.Filter {
grouped := make(map[collaboration.Filter_Type][]*collaboration.Filter)
for _, f := range filters {
grouped[f.Type] = append(grouped[f.Type], f)
}
return grouped
}

func granteeTypeToShareType(granteeType provider.GranteeType) int {
switch granteeType {
case provider.GranteeType_GRANTEE_TYPE_USER:
return shareTypeUser
case provider.GranteeType_GRANTEE_TYPE_GROUP:
return shareTypeGroup
}
return -1
}

// translateFilters translates the filters to sql queries
func translateFilters(filters []*collaboration.Filter) (string, []interface{}, error) {
var (
filterQuery string
params []interface{}
)

groupedFilters := groupFiltersByType(filters)
// If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator.
// That is why the filters got grouped by type.
// For every given filter type, iterate over the filters and if there are more than one combine them.
// Combine the different filter types using `AND`
var filterCounter = 0
for filterType, filters := range groupedFilters {
switch filterType {
case collaboration.Filter_TYPE_RESOURCE_ID:
filterQuery += "("
for i, f := range filters {
filterQuery += "item_source=?"
params = append(params, f.GetResourceId().OpaqueId)

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
case collaboration.Filter_TYPE_GRANTEE_TYPE:
filterQuery += "("
for i, f := range filters {
filterQuery += "share_type=?"
params = append(params, granteeTypeToShareType(f.GetGranteeType()))

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
case collaboration.Filter_TYPE_EXCLUDE_DENIALS:
// TODO this may change once the mapping of permission to share types is completed (cf. pkg/cbox/utils/conversions.go)
filterQuery += "permissions > 0"
default:
return "", nil, fmt.Errorf("filter type is not supported")
}
if filterCounter != len(groupedFilters)-1 {
filterQuery += " AND "
}
filterCounter++
}
return filterQuery, params, nil
}
5 changes: 5 additions & 0 deletions pkg/share/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/pkg/utils"
)

Expand Down Expand Up @@ -113,6 +114,10 @@ func MatchesFilter(share *collaboration.Share, filter *collaboration.Filter) boo
return utils.ResourceIDEqual(share.ResourceId, filter.GetResourceId())
case collaboration.Filter_TYPE_GRANTEE_TYPE:
return share.Grantee.Type == filter.GetGranteeType()
case collaboration.Filter_TYPE_EXCLUDE_DENIALS:
// This filter type is used to filter out "denial shares". These are currently implemented by having the permission "0".
// I.e. if the permission is 0 we don't want to show it.
return int(conversions.RoleFromResourcePermissions(share.Permissions.Permissions).OCSPermissions()) != 0
default:
return false
}
Expand Down

0 comments on commit 65d8cfc

Please sign in to comment.