github.com/cs3org/reva/v2@v2.27.7/pkg/share/manager/owncloudsql/owncloudsql.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package owncloudsql
    20  
    21  import (
    22  	"context"
    23  	"database/sql"
    24  	"fmt"
    25  	"path"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    31  	collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
    32  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    33  	typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
    34  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    35  	"github.com/cs3org/reva/v2/pkg/errtypes"
    36  	"github.com/cs3org/reva/v2/pkg/share"
    37  	"github.com/cs3org/reva/v2/pkg/share/manager/registry"
    38  	"github.com/cs3org/reva/v2/pkg/utils"
    39  	"github.com/mitchellh/mapstructure"
    40  	"github.com/pkg/errors"
    41  	"google.golang.org/genproto/protobuf/field_mask"
    42  
    43  	// Provides mysql drivers
    44  	_ "github.com/go-sql-driver/mysql"
    45  )
    46  
    47  const (
    48  	shareTypeUser  = 0
    49  	shareTypeGroup = 1
    50  )
    51  
    52  func init() {
    53  	registry.Register("owncloudsql", NewMysql)
    54  }
    55  
    56  type config struct {
    57  	GatewayAddr    string `mapstructure:"gateway_addr"`
    58  	StorageMountID string `mapstructure:"storage_mount_id"`
    59  	DbUsername     string `mapstructure:"db_username"`
    60  	DbPassword     string `mapstructure:"db_password"`
    61  	DbHost         string `mapstructure:"db_host"`
    62  	DbPort         int    `mapstructure:"db_port"`
    63  	DbName         string `mapstructure:"db_name"`
    64  }
    65  
    66  type mgr struct {
    67  	driver         string
    68  	db             *sql.DB
    69  	storageMountID string
    70  	userConverter  UserConverter
    71  }
    72  
    73  // NewMysql returns a new share manager connection to a mysql database
    74  func NewMysql(m map[string]interface{}) (share.Manager, error) {
    75  	c, err := parseConfig(m)
    76  	if err != nil {
    77  		err = errors.Wrap(err, "error creating a new manager")
    78  		return nil, err
    79  	}
    80  
    81  	db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DbUsername, c.DbPassword, c.DbHost, c.DbPort, c.DbName))
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	userConverter := NewGatewayUserConverter(c.GatewayAddr)
    87  
    88  	return New("mysql", db, c.StorageMountID, userConverter)
    89  }
    90  
    91  // New returns a new Cache instance connecting to the given sql.DB
    92  func New(driver string, db *sql.DB, storageMountID string, userConverter UserConverter) (share.Manager, error) {
    93  	return &mgr{
    94  		driver:         driver,
    95  		db:             db,
    96  		storageMountID: storageMountID,
    97  		userConverter:  userConverter,
    98  	}, nil
    99  }
   100  
   101  func parseConfig(m map[string]interface{}) (*config, error) {
   102  	c := &config{}
   103  	if err := mapstructure.Decode(m, c); err != nil {
   104  		return nil, err
   105  	}
   106  	return c, nil
   107  }
   108  
   109  func (m *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collaboration.ShareGrant) (*collaboration.Share, error) {
   110  	user := ctxpkg.ContextMustGetUser(ctx)
   111  
   112  	// do not allow share to myself or the owner if share is for a user
   113  	// TODO(labkode): should not this be caught already at the gw level?
   114  	if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER &&
   115  		(utils.UserEqual(g.Grantee.GetUserId(), user.Id) || utils.UserEqual(g.Grantee.GetUserId(), md.Owner)) {
   116  		return nil, errtypes.BadRequest("owncloudsql: owner/creator and grantee are the same")
   117  	}
   118  
   119  	// check if share already exists.
   120  	key := &collaboration.ShareKey{
   121  		Owner:      md.Owner,
   122  		ResourceId: md.Id,
   123  		Grantee:    g.Grantee,
   124  	}
   125  	_, err := m.getByKey(ctx, key)
   126  
   127  	// share already exists
   128  	if err == nil {
   129  		return nil, errtypes.AlreadyExists(key.String())
   130  	}
   131  
   132  	now := time.Now().Unix()
   133  	ts := &typespb.Timestamp{
   134  		Seconds: uint64(now),
   135  	}
   136  
   137  	owner, err := m.userConverter.UserIDToUserName(ctx, md.Owner)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	shareType, shareWith, err := m.formatGrantee(ctx, g.Grantee)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	itemType := resourceTypeToItem(md.Type)
   146  	targetPath := path.Join("/", path.Base(md.Path))
   147  	permissions := sharePermToInt(g.Permissions.Permissions)
   148  	itemSource := md.Id.OpaqueId
   149  	fileSource, err := strconv.ParseUint(itemSource, 10, 64)
   150  	if err != nil {
   151  		// it can be the case that the item source may be a character string
   152  		// we leave fileSource blank in that case
   153  		fileSource = 0
   154  	}
   155  
   156  	stmtString := "INSERT INTO oc_share (share_type,uid_owner,uid_initiator,item_type,item_source,file_source,permissions,stime,share_with,file_target) VALUES (?,?,?,?,?,?,?,?,?,?)"
   157  	stmtValues := []interface{}{shareType, owner, user.Username, itemType, itemSource, fileSource, permissions, now, shareWith, targetPath}
   158  
   159  	stmt, err := m.db.Prepare(stmtString)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	result, err := stmt.ExecContext(ctx, stmtValues...)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	lastID, err := result.LastInsertId()
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	return &collaboration.Share{
   173  		Id: &collaboration.ShareId{
   174  			OpaqueId: strconv.FormatInt(lastID, 10),
   175  		},
   176  		ResourceId:  md.Id,
   177  		Permissions: g.Permissions,
   178  		Grantee:     g.Grantee,
   179  		Owner:       md.Owner,
   180  		Creator:     user.Id,
   181  		Ctime:       ts,
   182  		Mtime:       ts,
   183  	}, nil
   184  }
   185  
   186  func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) {
   187  	var s *collaboration.Share
   188  	var err error
   189  	switch {
   190  	case ref.GetId() != nil:
   191  		s, err = m.getByID(ctx, ref.GetId())
   192  	case ref.GetKey() != nil:
   193  		s, err = m.getByKey(ctx, ref.GetKey())
   194  	default:
   195  		err = errtypes.NotFound(ref.String())
   196  	}
   197  
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	return s, nil
   203  }
   204  
   205  func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error {
   206  	uid := ctxpkg.ContextMustGetUser(ctx).Username
   207  	var query string
   208  	params := []interface{}{}
   209  	switch {
   210  	case ref.GetId() != nil:
   211  		query = "DELETE FROM oc_share where id=? AND (uid_owner=? or uid_initiator=?)"
   212  		params = append(params, ref.GetId().OpaqueId, uid, uid)
   213  	case ref.GetKey() != nil:
   214  		key := ref.GetKey()
   215  		shareType, shareWith, err := m.formatGrantee(ctx, key.Grantee)
   216  		if err != nil {
   217  			return err
   218  		}
   219  		owner := formatUserID(key.Owner)
   220  		query = "DELETE FROM oc_share WHERE uid_owner=? AND file_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)"
   221  		params = append(params, owner, key.ResourceId.OpaqueId, shareType, shareWith, uid, uid)
   222  	default:
   223  		return errtypes.NotFound(ref.String())
   224  	}
   225  
   226  	stmt, err := m.db.Prepare(query)
   227  	if err != nil {
   228  		return err
   229  	}
   230  	res, err := stmt.ExecContext(ctx, params...)
   231  	if err != nil {
   232  		return err
   233  	}
   234  
   235  	rowCnt, err := res.RowsAffected()
   236  	if err != nil {
   237  		return err
   238  	}
   239  	if rowCnt == 0 {
   240  		return errtypes.NotFound(ref.String())
   241  	}
   242  	return nil
   243  }
   244  
   245  func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions, updated *collaboration.Share, fieldMask *field_mask.FieldMask) (*collaboration.Share, error) {
   246  	permissions := sharePermToInt(p.Permissions)
   247  	uid := ctxpkg.ContextMustGetUser(ctx).Username
   248  
   249  	var query string
   250  	params := []interface{}{}
   251  	switch {
   252  	case ref.GetId() != nil:
   253  		query = "update oc_share set permissions=?,stime=? where id=? AND (uid_owner=? or uid_initiator=?)"
   254  		params = append(params, permissions, time.Now().Unix(), ref.GetId().OpaqueId, uid, uid)
   255  	case ref.GetKey() != nil:
   256  		key := ref.GetKey()
   257  		shareType, shareWith, err := m.formatGrantee(ctx, key.Grantee)
   258  		if err != nil {
   259  			return nil, err
   260  		}
   261  		owner := formatUserID(key.Owner)
   262  		query = "update oc_share set permissions=?,stime=? where (uid_owner=? or uid_initiator=?) AND file_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)"
   263  		params = append(params, permissions, time.Now().Unix(), owner, owner, key.ResourceId.OpaqueId, shareType, shareWith, uid, uid)
   264  	default:
   265  		return nil, errtypes.NotFound(ref.String())
   266  	}
   267  
   268  	stmt, err := m.db.Prepare(query)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  	if _, err = stmt.ExecContext(ctx, params...); err != nil {
   273  		return nil, err
   274  	}
   275  
   276  	return m.GetShare(ctx, ref)
   277  }
   278  
   279  func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
   280  	uid := ctxpkg.ContextMustGetUser(ctx).Username
   281  	query := `
   282  		SELECT
   283  			coalesce(s.uid_owner, '') as uid_owner, coalesce(s.uid_initiator, '') as uid_initiator,
   284  			coalesce(s.share_with, '') as share_with, coalesce(s.file_source, '') as file_source,
   285  			s.file_target, s.id, s.stime, s.permissions, s.share_type, fc.storage as storage
   286  		FROM oc_share s
   287  		LEFT JOIN oc_filecache fc ON fc.fileid = file_source
   288  		WHERE (uid_owner=? or uid_initiator=?)
   289  	`
   290  	params := []interface{}{uid, uid}
   291  
   292  	var (
   293  		filterQuery  string
   294  		filterParams []interface{}
   295  		err          error
   296  	)
   297  	if len(filters) == 0 {
   298  		filterQuery += "(share_type=? OR share_type=?)"
   299  		params = append(params, shareTypeUser)
   300  		params = append(params, shareTypeGroup)
   301  	} else {
   302  		filterQuery, filterParams, err = translateFilters(filters)
   303  		if err != nil {
   304  			return nil, err
   305  		}
   306  		params = append(params, filterParams...)
   307  	}
   308  
   309  	if filterQuery != "" {
   310  		query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
   311  	}
   312  
   313  	rows, err := m.db.QueryContext(ctx, query, params...)
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  	defer rows.Close()
   318  
   319  	var s DBShare
   320  	shares := []*collaboration.Share{}
   321  	for rows.Next() {
   322  		if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.ItemStorage); err != nil {
   323  			continue
   324  		}
   325  		share, err := m.convertToCS3Share(ctx, s, m.storageMountID)
   326  		if err != nil {
   327  			return nil, err
   328  		}
   329  		shares = append(shares, share)
   330  	}
   331  	if err = rows.Err(); err != nil {
   332  		return nil, err
   333  	}
   334  
   335  	return shares, nil
   336  }
   337  
   338  // we list the shares that are targeted to the user in context or to the user groups.
   339  func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter, forUser *userpb.UserId) ([]*collaboration.ReceivedShare, error) {
   340  	user := ctxpkg.ContextMustGetUser(ctx)
   341  	if user.GetId().GetType() == userpb.UserType_USER_TYPE_SERVICE {
   342  		u, err := m.userConverter.GetUser(forUser)
   343  		if err != nil {
   344  			return nil, errtypes.BadRequest("user not found")
   345  		}
   346  		user = u
   347  	}
   348  	uid := user.Username
   349  
   350  	params := []interface{}{uid, uid, uid}
   351  	for _, v := range user.Groups {
   352  		params = append(params, v)
   353  	}
   354  
   355  	homeConcat := ""
   356  	if m.driver == "mysql" { // mysql concat
   357  		homeConcat = "storages.id = CONCAT('home::', s.uid_owner)"
   358  	} else { // sqlite3 concat
   359  		homeConcat = "storages.id = 'home::' || s.uid_owner"
   360  	}
   361  	userSelect := ""
   362  	if len(user.Groups) > 0 {
   363  		userSelect = "AND ((share_type != 1 AND share_with=?) OR (share_type = 1 AND share_with in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))"
   364  	} else {
   365  		userSelect = "AND (share_type != 1 AND share_with=?)"
   366  	}
   367  	query := `
   368  	WITH results AS
   369  		(
   370  			SELECT s.*, storages.numeric_id FROM oc_share s
   371  			LEFT JOIN oc_storages storages ON ` + homeConcat + `
   372  			WHERE (uid_owner != ? AND uid_initiator != ?) ` + userSelect + `
   373  		)
   374  	SELECT COALESCE(r.uid_owner, '') AS uid_owner, COALESCE(r.uid_initiator, '') AS uid_initiator, COALESCE(r.share_with, '')
   375  	AS share_with, COALESCE(r.file_source, '') AS file_source, COALESCE(r2.file_target, r.file_target), r.id, r.stime, r.permissions, r.share_type, COALESCE(r2.accepted, r.accepted),
   376  	r.numeric_id, COALESCE(r.parent, -1) AS parent FROM results r LEFT JOIN results r2 ON r.id = r2.parent WHERE r.parent IS NULL`
   377  
   378  	filterQuery, filterParams, err := translateFilters(filters)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  	params = append(params, filterParams...)
   383  
   384  	if filterQuery != "" {
   385  		query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
   386  	}
   387  	query += ";"
   388  	rows, err := m.db.QueryContext(ctx, query, params...)
   389  	if err != nil {
   390  		return nil, err
   391  	}
   392  	defer rows.Close()
   393  
   394  	var s DBShare
   395  	shares := []*collaboration.ReceivedShare{}
   396  	for rows.Next() {
   397  		if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State, &s.ItemStorage, &s.Parent); err != nil {
   398  			continue
   399  		}
   400  		share, err := m.convertToCS3ReceivedShare(ctx, s, m.storageMountID)
   401  		if err != nil {
   402  			return nil, err
   403  		}
   404  		shares = append(shares, share)
   405  	}
   406  	if err = rows.Err(); err != nil {
   407  		return nil, err
   408  	}
   409  
   410  	return shares, nil
   411  }
   412  
   413  func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) {
   414  	var s *collaboration.ReceivedShare
   415  	var err error
   416  	switch {
   417  	case ref.GetId() != nil:
   418  		s, err = m.getReceivedByID(ctx, ref.GetId())
   419  	case ref.GetKey() != nil:
   420  		s, err = m.getReceivedByKey(ctx, ref.GetKey())
   421  	default:
   422  		err = errtypes.NotFound(ref.String())
   423  	}
   424  
   425  	if err != nil {
   426  		return nil, err
   427  	}
   428  
   429  	return s, nil
   430  
   431  }
   432  
   433  func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, _ *userpb.UserId) (*collaboration.ReceivedShare, error) {
   434  	// TODO: How to inject the uid when a UserId is set? override it in the ctx? Add parameter to GetReceivedShare?
   435  	rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: receivedShare.Share.Id}})
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  
   440  	fields := []string{}
   441  	params := []interface{}{}
   442  	for i := range fieldMask.Paths {
   443  		switch fieldMask.Paths[i] {
   444  		case "state":
   445  			rs.State = receivedShare.State
   446  			fields = append(fields, "accepted=?")
   447  			switch rs.State {
   448  			case collaboration.ShareState_SHARE_STATE_REJECTED:
   449  				params = append(params, 2)
   450  			case collaboration.ShareState_SHARE_STATE_ACCEPTED:
   451  				params = append(params, 0)
   452  			}
   453  		case "mount_point":
   454  			fields = append(fields, "file_target=?")
   455  			rs.MountPoint = receivedShare.MountPoint
   456  			params = append(params, rs.MountPoint.Path)
   457  		case "hidden":
   458  			continue
   459  		default:
   460  			return nil, errtypes.NotSupported("updating " + fieldMask.Paths[i] + " is not supported")
   461  		}
   462  	}
   463  
   464  	if len(fields) == 0 {
   465  		return nil, fmt.Errorf("no valid field provided in the fieldmask")
   466  	}
   467  
   468  	updateReceivedShare := func(column string) error {
   469  		query := "update oc_share set "
   470  		query += strings.Join(fields, ",")
   471  		query += fmt.Sprintf(" where %s=?", column)
   472  		params := append(params, rs.Share.Id.OpaqueId)
   473  
   474  		stmt, err := m.db.Prepare(query)
   475  		if err != nil {
   476  			return err
   477  		}
   478  		res, err := stmt.ExecContext(ctx, params...)
   479  		if err != nil {
   480  			return err
   481  		}
   482  		affected, err := res.RowsAffected()
   483  		if err != nil {
   484  			return err
   485  		}
   486  		if affected < 1 {
   487  			return fmt.Errorf("No rows updated")
   488  		}
   489  		return nil
   490  	}
   491  	err = updateReceivedShare("parent") // Try to update the child state in case of group shares first
   492  	if err != nil {
   493  		err = updateReceivedShare("id")
   494  	}
   495  	if err != nil {
   496  		return nil, err
   497  	}
   498  
   499  	return rs, nil
   500  }
   501  
   502  func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId) (*collaboration.Share, error) {
   503  	uid := ctxpkg.ContextMustGetUser(ctx).Username
   504  	s := DBShare{ID: id.OpaqueId}
   505  	query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(file_source, '') as file_source, file_target, stime, permissions, share_type FROM oc_share WHERE id=? AND (uid_owner=? or uid_initiator=?)"
   506  	if err := m.db.QueryRowContext(ctx, query, id.OpaqueId, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.STime, &s.Permissions, &s.ShareType); err != nil {
   507  		if err == sql.ErrNoRows {
   508  			return nil, errtypes.NotFound(id.OpaqueId)
   509  		}
   510  		return nil, err
   511  	}
   512  	return m.convertToCS3Share(ctx, s, m.storageMountID)
   513  }
   514  
   515  func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.Share, error) {
   516  	owner, err := m.userConverter.UserIDToUserName(ctx, key.Owner)
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  	uid := ctxpkg.ContextMustGetUser(ctx).Username
   521  
   522  	s := DBShare{}
   523  	shareType, shareWith, err := m.formatGrantee(ctx, key.Grantee)
   524  	if err != nil {
   525  		return nil, err
   526  	}
   527  	query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(file_source, '') as file_source, file_target, id, stime, permissions, share_type FROM oc_share WHERE uid_owner=? AND file_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)"
   528  	if err = m.db.QueryRowContext(ctx, query, owner, key.ResourceId.StorageId, shareType, shareWith, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil {
   529  		if err == sql.ErrNoRows {
   530  			return nil, errtypes.NotFound(key.String())
   531  		}
   532  		return nil, err
   533  	}
   534  	return m.convertToCS3Share(ctx, s, m.storageMountID)
   535  }
   536  
   537  func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId) (*collaboration.ReceivedShare, error) {
   538  	user := ctxpkg.ContextMustGetUser(ctx)
   539  	uid := user.Username
   540  
   541  	params := []interface{}{id.OpaqueId, id.OpaqueId, uid}
   542  	for _, v := range user.Groups {
   543  		params = append(params, v)
   544  	}
   545  
   546  	homeConcat := ""
   547  	if m.driver == "mysql" { // mysql concat
   548  		homeConcat = "storages.id = CONCAT('home::', s.uid_owner)"
   549  	} else { // sqlite3 concat
   550  		homeConcat = "storages.id = 'home::' || s.uid_owner"
   551  	}
   552  	userSelect := ""
   553  	if len(user.Groups) > 0 {
   554  		userSelect = "AND ((share_type != 1 AND share_with=?) OR (share_type = 1 AND share_with in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))"
   555  	} else {
   556  		userSelect = "AND (share_type != 1 AND share_with=?)"
   557  	}
   558  
   559  	query := `
   560  	WITH results AS
   561  	(
   562  		SELECT s.*, storages.numeric_id 
   563  		FROM oc_share s
   564  		LEFT JOIN oc_storages storages ON ` + homeConcat + `
   565  		WHERE s.id=? OR s.parent=? ` + userSelect + `
   566  	)
   567  	SELECT COALESCE(r.uid_owner, '') AS uid_owner, COALESCE(r.uid_initiator, '') AS uid_initiator, COALESCE(r.share_with, '')
   568  		AS share_with, COALESCE(r.file_source, '') AS file_source, COALESCE(r2.file_target, r.file_target), r.id, r.stime, r.permissions, r.share_type, COALESCE(r2.accepted, r.accepted),
   569  		r.numeric_id, COALESCE(r.parent, -1) AS parent 
   570  	FROM results r 
   571  	LEFT JOIN results r2 ON r.id = r2.parent 
   572  	WHERE r.parent IS NULL;
   573  	`
   574  
   575  	s := DBShare{}
   576  	if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State, &s.ItemStorage, &s.Parent); err != nil {
   577  		if err == sql.ErrNoRows {
   578  			return nil, errtypes.NotFound(id.OpaqueId)
   579  		}
   580  		return nil, err
   581  	}
   582  	return m.convertToCS3ReceivedShare(ctx, s, m.storageMountID)
   583  }
   584  
   585  func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.ReceivedShare, error) {
   586  	user := ctxpkg.ContextMustGetUser(ctx)
   587  	uid := user.Username
   588  
   589  	shareType, shareWith, err := m.formatGrantee(ctx, key.Grantee)
   590  	if err != nil {
   591  		return nil, err
   592  	}
   593  	params := []interface{}{uid, formatUserID(key.Owner), key.ResourceId.StorageId, key.ResourceId.OpaqueId, shareType, shareWith, shareWith}
   594  	for _, v := range user.Groups {
   595  		params = append(params, v)
   596  	}
   597  
   598  	s := DBShare{}
   599  	query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(file_source, '') as file_source, file_target, ts.id, stime, permissions, share_type, accepted FROM oc_share ts WHERE uid_owner=? AND file_source=? AND share_type=? AND share_with=? "
   600  	if len(user.Groups) > 0 {
   601  		query += "AND (share_with=? OR share_with in (?" + strings.Repeat(",?", len(user.Groups)-1) + "))"
   602  	} else {
   603  		query += "AND (share_with=?)"
   604  	}
   605  
   606  	if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil {
   607  		if err == sql.ErrNoRows {
   608  			return nil, errtypes.NotFound(key.String())
   609  		}
   610  		return nil, err
   611  	}
   612  	return m.convertToCS3ReceivedShare(ctx, s, m.storageMountID)
   613  }
   614  
   615  func granteeTypeToShareType(granteeType provider.GranteeType) int {
   616  	switch granteeType {
   617  	case provider.GranteeType_GRANTEE_TYPE_USER:
   618  		return shareTypeUser
   619  	case provider.GranteeType_GRANTEE_TYPE_GROUP:
   620  		return shareTypeGroup
   621  	}
   622  	return -1
   623  }
   624  
   625  // translateFilters translates the filters to sql queries
   626  func translateFilters(filters []*collaboration.Filter) (string, []interface{}, error) {
   627  	var (
   628  		filterQuery string
   629  		params      []interface{}
   630  	)
   631  
   632  	groupedFilters := share.GroupFiltersByType(filters)
   633  	// If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator.
   634  	// That is why the filters got grouped by type.
   635  	// For every given filter type, iterate over the filters and if there are more than one combine them.
   636  	// Combine the different filter types using `AND`
   637  	var filterCounter = 0
   638  	for filterType, filters := range groupedFilters {
   639  		switch filterType {
   640  		case collaboration.Filter_TYPE_RESOURCE_ID:
   641  			filterQuery += "("
   642  			for i, f := range filters {
   643  				filterQuery += "file_source=?"
   644  				params = append(params, f.GetResourceId().OpaqueId)
   645  
   646  				if i != len(filters)-1 {
   647  					filterQuery += " OR "
   648  				}
   649  			}
   650  			filterQuery += ")"
   651  		case collaboration.Filter_TYPE_GRANTEE_TYPE:
   652  			filterQuery += "("
   653  			for i, f := range filters {
   654  				filterQuery += "r.share_type=?"
   655  				params = append(params, granteeTypeToShareType(f.GetGranteeType()))
   656  
   657  				if i != len(filters)-1 {
   658  					filterQuery += " OR "
   659  				}
   660  			}
   661  			filterQuery += ")"
   662  		case collaboration.Filter_TYPE_EXCLUDE_DENIALS:
   663  			// TODO this may change once the mapping of permission to share types is completed (cf. pkg/cbox/utils/conversions.go)
   664  			filterQuery += "r.permissions > 0"
   665  		default:
   666  			return "", nil, fmt.Errorf("filter type is not supported")
   667  		}
   668  		if filterCounter != len(groupedFilters)-1 {
   669  			filterQuery += " AND "
   670  		}
   671  		filterCounter++
   672  	}
   673  	return filterQuery, params, nil
   674  }