github.com/cs3org/reva/v2@v2.27.7/pkg/cbox/share/sql/sql.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 sql
    20  
    21  import (
    22  	"context"
    23  	"database/sql"
    24  	"fmt"
    25  	"path"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
    31  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    32  	collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
    33  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    34  	typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
    35  	conversions "github.com/cs3org/reva/v2/pkg/cbox/utils"
    36  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    37  	"github.com/cs3org/reva/v2/pkg/errtypes"
    38  	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
    39  	"github.com/cs3org/reva/v2/pkg/share"
    40  	"github.com/cs3org/reva/v2/pkg/share/manager/registry"
    41  	"github.com/cs3org/reva/v2/pkg/utils"
    42  	"github.com/mitchellh/mapstructure"
    43  	"github.com/pkg/errors"
    44  	"google.golang.org/genproto/protobuf/field_mask"
    45  
    46  	// Provides mysql drivers
    47  	_ "github.com/go-sql-driver/mysql"
    48  )
    49  
    50  const (
    51  	shareTypeUser  = 0
    52  	shareTypeGroup = 1
    53  )
    54  
    55  func init() {
    56  	registry.Register("sql", New)
    57  }
    58  
    59  type config struct {
    60  	DbUsername string `mapstructure:"db_username"`
    61  	DbPassword string `mapstructure:"db_password"`
    62  	DbHost     string `mapstructure:"db_host"`
    63  	DbPort     int    `mapstructure:"db_port"`
    64  	DbName     string `mapstructure:"db_name"`
    65  	GatewaySvc string `mapstructure:"gatewaysvc"`
    66  }
    67  
    68  type mgr struct {
    69  	c      *config
    70  	db     *sql.DB
    71  	client gatewayv1beta1.GatewayAPIClient
    72  }
    73  
    74  // New returns a new share manager.
    75  func New(m map[string]interface{}) (share.Manager, error) {
    76  	c, err := parseConfig(m)
    77  	if err != nil {
    78  		err = errors.Wrap(err, "error creating a new manager")
    79  		return nil, err
    80  	}
    81  
    82  	db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DbUsername, c.DbPassword, c.DbHost, c.DbPort, c.DbName))
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	gw, err := pool.GetGatewayServiceClient(c.GatewaySvc)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	return &mgr{
    93  		c:      c,
    94  		db:     db,
    95  		client: gw,
    96  	}, nil
    97  }
    98  
    99  func parseConfig(m map[string]interface{}) (*config, error) {
   100  	c := &config{}
   101  	if err := mapstructure.Decode(m, c); err != nil {
   102  		return nil, err
   103  	}
   104  	return c, nil
   105  }
   106  
   107  func (m *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collaboration.ShareGrant) (*collaboration.Share, error) {
   108  	user := ctxpkg.ContextMustGetUser(ctx)
   109  
   110  	// do not allow share to myself or the owner if share is for a user
   111  	// TODO(labkode): should not this be caught already at the gw level?
   112  	if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER &&
   113  		(utils.UserEqual(g.Grantee.GetUserId(), user.Id) || utils.UserEqual(g.Grantee.GetUserId(), md.Owner)) {
   114  		return nil, errors.New("sql: owner/creator and grantee are the same")
   115  	}
   116  
   117  	// check if share already exists.
   118  	key := &collaboration.ShareKey{
   119  		Owner:      md.Owner,
   120  		ResourceId: md.Id,
   121  		Grantee:    g.Grantee,
   122  	}
   123  	_, err := m.getByKey(ctx, key)
   124  
   125  	// share already exists
   126  	if err == nil {
   127  		return nil, errtypes.AlreadyExists(key.String())
   128  	}
   129  
   130  	now := time.Now().Unix()
   131  	ts := &typespb.Timestamp{
   132  		Seconds: uint64(now),
   133  	}
   134  
   135  	shareType, shareWith := conversions.FormatGrantee(g.Grantee)
   136  	itemType := conversions.ResourceTypeToItem(md.Type)
   137  	targetPath := path.Join("/", path.Base(md.Path))
   138  	permissions := conversions.SharePermToInt(g.Permissions.Permissions)
   139  	prefix := md.Id.SpaceId
   140  	itemSource := md.Id.OpaqueId
   141  	fileSource, err := strconv.ParseUint(itemSource, 10, 64)
   142  	if err != nil {
   143  		// it can be the case that the item source may be a character string
   144  		// we leave fileSource blank in that case
   145  		fileSource = 0
   146  	}
   147  
   148  	stmtString := "insert into oc_share set share_type=?,uid_owner=?,uid_initiator=?,item_type=?,fileid_prefix=?,item_source=?,file_source=?,permissions=?,stime=?,share_with=?,file_target=?"
   149  	stmtValues := []interface{}{shareType, conversions.FormatUserID(md.Owner), conversions.FormatUserID(user.Id), itemType, prefix, itemSource, fileSource, permissions, now, shareWith, targetPath}
   150  
   151  	stmt, err := m.db.Prepare(stmtString)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	result, err := stmt.Exec(stmtValues...)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	lastID, err := result.LastInsertId()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	return &collaboration.Share{
   165  		Id: &collaboration.ShareId{
   166  			OpaqueId: strconv.FormatInt(lastID, 10),
   167  		},
   168  		ResourceId:  md.Id,
   169  		Permissions: g.Permissions,
   170  		Grantee:     g.Grantee,
   171  		Owner:       md.Owner,
   172  		Creator:     user.Id,
   173  		Ctime:       ts,
   174  		Mtime:       ts,
   175  	}, nil
   176  }
   177  
   178  func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId) (*collaboration.Share, error) {
   179  	uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
   180  	s := conversions.DBShare{ID: id.OpaqueId}
   181  	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, coalesce(item_type, '') as item_type, stime, permissions, share_type FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND id=? AND (uid_owner=? or uid_initiator=?)"
   182  	if err := m.db.QueryRow(query, id.OpaqueId, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.STime, &s.Permissions, &s.ShareType); err != nil {
   183  		if err == sql.ErrNoRows {
   184  			return nil, errtypes.NotFound(id.OpaqueId)
   185  		}
   186  		return nil, err
   187  	}
   188  	share, err := conversions.ConvertToCS3Share(ctx, m.client, s)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	return share, nil
   193  }
   194  
   195  func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.Share, error) {
   196  	owner := conversions.FormatUserID(key.Owner)
   197  	uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
   198  
   199  	s := conversions.DBShare{}
   200  	shareType, shareWith := conversions.FormatGrantee(key.Grantee)
   201  	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, coalesce(item_type, '') as item_type, id, stime, permissions, share_type FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND uid_owner=? AND fileid_prefix=? AND item_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)"
   202  	if err := m.db.QueryRow(query, owner, key.ResourceId.SpaceId, key.ResourceId.OpaqueId, shareType, shareWith, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil {
   203  		if err == sql.ErrNoRows {
   204  			return nil, errtypes.NotFound(key.String())
   205  		}
   206  		return nil, err
   207  	}
   208  	share, err := conversions.ConvertToCS3Share(ctx, m.client, s)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	return share, nil
   213  }
   214  
   215  func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) {
   216  	var s *collaboration.Share
   217  	var err error
   218  	switch {
   219  	case ref.GetId() != nil:
   220  		s, err = m.getByID(ctx, ref.GetId())
   221  	case ref.GetKey() != nil:
   222  		s, err = m.getByKey(ctx, ref.GetKey())
   223  	default:
   224  		err = errtypes.NotFound(ref.String())
   225  	}
   226  
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	return s, nil
   232  }
   233  
   234  func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error {
   235  	uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
   236  	var query string
   237  	params := []interface{}{}
   238  	switch {
   239  	case ref.GetId() != nil:
   240  		query = "delete from oc_share where id=? AND (uid_owner=? or uid_initiator=?)"
   241  		params = append(params, ref.GetId().OpaqueId, uid, uid)
   242  	case ref.GetKey() != nil:
   243  		key := ref.GetKey()
   244  		shareType, shareWith := conversions.FormatGrantee(key.Grantee)
   245  		owner := conversions.FormatUserID(key.Owner)
   246  		query = "delete from oc_share where uid_owner=? AND fileid_prefix=? AND item_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)"
   247  		params = append(params, owner, key.ResourceId.SpaceId, key.ResourceId.OpaqueId, shareType, shareWith, uid, uid)
   248  	default:
   249  		return errtypes.NotFound(ref.String())
   250  	}
   251  
   252  	stmt, err := m.db.Prepare(query)
   253  	if err != nil {
   254  		return err
   255  	}
   256  	res, err := stmt.Exec(params...)
   257  	if err != nil {
   258  		return err
   259  	}
   260  
   261  	rowCnt, err := res.RowsAffected()
   262  	if err != nil {
   263  		return err
   264  	}
   265  	if rowCnt == 0 {
   266  		return errtypes.NotFound(ref.String())
   267  	}
   268  	return nil
   269  }
   270  
   271  func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions, updated *collaboration.Share, fieldMask *field_mask.FieldMask) (*collaboration.Share, error) {
   272  	permissions := conversions.SharePermToInt(p.Permissions)
   273  	uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
   274  
   275  	var query string
   276  	params := []interface{}{}
   277  	switch {
   278  	case ref.GetId() != nil:
   279  		query = "update oc_share set permissions=?,stime=? where id=? AND (uid_owner=? or uid_initiator=?)"
   280  		params = append(params, permissions, time.Now().Unix(), ref.GetId().OpaqueId, uid, uid)
   281  	case ref.GetKey() != nil:
   282  		key := ref.GetKey()
   283  		shareType, shareWith := conversions.FormatGrantee(key.Grantee)
   284  		owner := conversions.FormatUserID(key.Owner)
   285  		query = "update oc_share set permissions=?,stime=? where (uid_owner=? or uid_initiator=?) AND fileid_prefix=? AND item_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)"
   286  		params = append(params, permissions, time.Now().Unix(), owner, owner, key.ResourceId.SpaceId, key.ResourceId.OpaqueId, shareType, shareWith, uid, uid)
   287  	default:
   288  		return nil, errtypes.NotFound(ref.String())
   289  	}
   290  
   291  	stmt, err := m.db.Prepare(query)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	if _, err = stmt.Exec(params...); err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	return m.GetShare(ctx, ref)
   300  }
   301  
   302  func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
   303  	uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
   304  	query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with,
   305  				coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type,
   306  			  	id, stime, permissions, share_type
   307  			  FROM oc_share
   308  			  WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner=? or uid_initiator=?) AND (share_type=? OR share_type=?)`
   309  	params := []interface{}{uid, uid, shareTypeUser, shareTypeGroup}
   310  
   311  	if len(filters) > 0 {
   312  		filterQuery, filterParams, err := translateFilters(filters)
   313  		if err != nil {
   314  			return nil, err
   315  		}
   316  		params = append(params, filterParams...)
   317  		if filterQuery != "" {
   318  			query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
   319  		}
   320  	}
   321  
   322  	rows, err := m.db.Query(query, params...)
   323  	if err != nil {
   324  		return nil, err
   325  	}
   326  	defer rows.Close()
   327  
   328  	var s conversions.DBShare
   329  	shares := []*collaboration.Share{}
   330  	for rows.Next() {
   331  		if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil {
   332  			continue
   333  		}
   334  		share, err := conversions.ConvertToCS3Share(ctx, m.client, s)
   335  		if err != nil {
   336  			continue
   337  		}
   338  		shares = append(shares, share)
   339  	}
   340  	if err = rows.Err(); err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	return shares, nil
   345  }
   346  
   347  // we list the shares that are targeted to the user in context or to the user groups.
   348  func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter, _ *userpb.UserId) ([]*collaboration.ReceivedShare, error) {
   349  	user := ctxpkg.ContextMustGetUser(ctx)
   350  	uid := conversions.FormatUserID(user.Id)
   351  
   352  	params := []interface{}{uid, uid, uid, uid}
   353  	for _, v := range user.Groups {
   354  		params = append(params, v)
   355  	}
   356  
   357  	query := `SELECT coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with,
   358  	            coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(file_target, '') as file_target,
   359  				ts.id, stime, permissions, share_type, coalesce(tr.state, 0) as state
   360  			  FROM oc_share ts LEFT JOIN oc_share_status tr ON (ts.id = tr.id AND tr.recipient = ?)
   361  			  WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner != ? AND uid_initiator != ?)`
   362  	if len(user.Groups) > 0 {
   363  		query += " AND ((share_with=? AND share_type = 0) OR (share_type = 1 AND share_with in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))"
   364  	} else {
   365  		query += " AND (share_with=? AND share_type = 0)"
   366  	}
   367  
   368  	filterQuery, filterParams, err := translateFilters(filters)
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  	params = append(params, filterParams...)
   373  
   374  	if filterQuery != "" {
   375  		query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
   376  	}
   377  
   378  	rows, err := m.db.Query(query, params...)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  	defer rows.Close()
   383  
   384  	var s conversions.DBShare
   385  	shares := []*collaboration.ReceivedShare{}
   386  	for rows.Next() {
   387  		if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil {
   388  			continue
   389  		}
   390  		share, err := conversions.ConvertToCS3ReceivedShare(ctx, m.client, s)
   391  		if err != nil {
   392  			continue
   393  		}
   394  		shares = append(shares, share)
   395  	}
   396  	if err = rows.Err(); err != nil {
   397  		return nil, err
   398  	}
   399  
   400  	return shares, nil
   401  }
   402  
   403  func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId) (*collaboration.ReceivedShare, error) {
   404  	user := ctxpkg.ContextMustGetUser(ctx)
   405  	uid := conversions.FormatUserID(user.Id)
   406  
   407  	params := []interface{}{uid, id.OpaqueId, uid}
   408  	for _, v := range user.Groups {
   409  		params = append(params, v)
   410  	}
   411  
   412  	s := conversions.DBShare{ID: id.OpaqueId}
   413  	query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with,
   414  			    coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(file_target, '') as file_target,
   415  				stime, permissions, share_type, coalesce(tr.state, 0) as state
   416  			  FROM oc_share ts LEFT JOIN oc_share_status tr ON (ts.id = tr.id AND tr.recipient = ?)
   417  			  WHERE (orphan = 0 or orphan IS NULL) AND ts.id=?`
   418  	if len(user.Groups) > 0 {
   419  		query += " AND ((share_with=? AND share_type = 0) OR (share_type = 1 AND share_with in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))"
   420  	} else {
   421  		query += " AND (share_with=?  AND share_type = 0)"
   422  	}
   423  	if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.FileTarget, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil {
   424  		if err == sql.ErrNoRows {
   425  			return nil, errtypes.NotFound(id.OpaqueId)
   426  		}
   427  		return nil, err
   428  	}
   429  	share, err := conversions.ConvertToCS3ReceivedShare(ctx, m.client, s)
   430  	if err != nil {
   431  		return nil, err
   432  	}
   433  	return share, nil
   434  }
   435  
   436  func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.ReceivedShare, error) {
   437  	user := ctxpkg.ContextMustGetUser(ctx)
   438  	uid := conversions.FormatUserID(user.Id)
   439  
   440  	shareType, shareWith := conversions.FormatGrantee(key.Grantee)
   441  	params := []interface{}{uid, conversions.FormatUserID(key.Owner), key.GetResourceId().SpaceId, key.ResourceId.OpaqueId, shareType, shareWith, shareWith}
   442  	for _, v := range user.Groups {
   443  		params = append(params, v)
   444  	}
   445  
   446  	s := conversions.DBShare{}
   447  	query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with,
   448  	            coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(file_target, '') as file_target,
   449  				ts.id, stime, permissions, share_type, coalesce(tr.state, 0) as state
   450  			  FROM oc_share ts LEFT JOIN oc_share_status tr ON (ts.id = tr.id AND tr.recipient = ?)
   451  			  WHERE (orphan = 0 or orphan IS NULL) AND uid_owner=? AND fileid_prefix=? AND item_source=? AND share_type=? AND share_with=?`
   452  	if len(user.Groups) > 0 {
   453  		query += " AND ((share_with=? AND share_type = 0) OR (share_type = 1 AND share_with in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))"
   454  	} else {
   455  		query += " AND (share_with=? AND share_type = 0)"
   456  	}
   457  
   458  	if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil {
   459  		if err == sql.ErrNoRows {
   460  			return nil, errtypes.NotFound(key.String())
   461  		}
   462  		return nil, err
   463  	}
   464  	share, err := conversions.ConvertToCS3ReceivedShare(ctx, m.client, s)
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  	return share, nil
   469  }
   470  
   471  func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) {
   472  	var s *collaboration.ReceivedShare
   473  	var err error
   474  	switch {
   475  	case ref.GetId() != nil:
   476  		s, err = m.getReceivedByID(ctx, ref.GetId())
   477  	case ref.GetKey() != nil:
   478  		s, err = m.getReceivedByKey(ctx, ref.GetKey())
   479  	default:
   480  		err = errtypes.NotFound(ref.String())
   481  	}
   482  
   483  	if err != nil {
   484  		return nil, err
   485  	}
   486  
   487  	return s, nil
   488  
   489  }
   490  
   491  func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask, _ *userpb.UserId) (*collaboration.ReceivedShare, error) {
   492  	user := ctxpkg.ContextMustGetUser(ctx)
   493  
   494  	rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Share.Id}})
   495  	if err != nil {
   496  		return nil, err
   497  	}
   498  
   499  	for i := range fieldMask.Paths {
   500  		switch fieldMask.Paths[i] {
   501  		case "state":
   502  			rs.State = share.State
   503  		case "mount_point":
   504  			rs.MountPoint = share.MountPoint
   505  		default:
   506  			return nil, errtypes.NotSupported("updating " + fieldMask.Paths[i] + " is not supported")
   507  		}
   508  	}
   509  
   510  	state := 0
   511  	switch rs.GetState() {
   512  	case collaboration.ShareState_SHARE_STATE_REJECTED:
   513  		state = -1
   514  	case collaboration.ShareState_SHARE_STATE_ACCEPTED:
   515  		state = 1
   516  	}
   517  
   518  	params := []interface{}{rs.Share.Id.OpaqueId, conversions.FormatUserID(user.Id), state, state}
   519  	query := "insert into oc_share_status(id, recipient, state) values(?, ?, ?) ON DUPLICATE KEY UPDATE state = ?"
   520  
   521  	stmt, err := m.db.Prepare(query)
   522  	if err != nil {
   523  		return nil, err
   524  	}
   525  	_, err = stmt.Exec(params...)
   526  	if err != nil {
   527  		return nil, err
   528  	}
   529  
   530  	return rs, nil
   531  }
   532  
   533  func granteeTypeToShareType(granteeType provider.GranteeType) int {
   534  	switch granteeType {
   535  	case provider.GranteeType_GRANTEE_TYPE_USER:
   536  		return shareTypeUser
   537  	case provider.GranteeType_GRANTEE_TYPE_GROUP:
   538  		return shareTypeGroup
   539  	}
   540  	return -1
   541  }
   542  
   543  // translateFilters translates the filters to sql queries
   544  func translateFilters(filters []*collaboration.Filter) (string, []interface{}, error) {
   545  	var (
   546  		filterQuery string
   547  		params      []interface{}
   548  	)
   549  
   550  	groupedFilters := share.GroupFiltersByType(filters)
   551  	// If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator.
   552  	// That is why the filters got grouped by type.
   553  	// For every given filter type, iterate over the filters and if there are more than one combine them.
   554  	// Combine the different filter types using `AND`
   555  	var filterCounter = 0
   556  	for filterType, filters := range groupedFilters {
   557  		switch filterType {
   558  		case collaboration.Filter_TYPE_RESOURCE_ID:
   559  			filterQuery += "("
   560  			for i, f := range filters {
   561  				filterQuery += "(fileid_prefix =? AND item_source=?)"
   562  				params = append(params, f.GetResourceId().SpaceId, f.GetResourceId().OpaqueId)
   563  
   564  				if i != len(filters)-1 {
   565  					filterQuery += " OR "
   566  				}
   567  			}
   568  			filterQuery += ")"
   569  		case collaboration.Filter_TYPE_GRANTEE_TYPE:
   570  			filterQuery += "("
   571  			for i, f := range filters {
   572  				filterQuery += "share_type=?"
   573  				params = append(params, granteeTypeToShareType(f.GetGranteeType()))
   574  
   575  				if i != len(filters)-1 {
   576  					filterQuery += " OR "
   577  				}
   578  			}
   579  			filterQuery += ")"
   580  		case collaboration.Filter_TYPE_EXCLUDE_DENIALS:
   581  			// TODO this may change once the mapping of permission to share types is completed (cf. pkg/cbox/utils/conversions.go)
   582  			filterQuery += "(permissions > 0)"
   583  		default:
   584  			return "", nil, fmt.Errorf("filter type is not supported")
   585  		}
   586  		if filterCounter != len(groupedFilters)-1 {
   587  			filterQuery += " AND "
   588  		}
   589  		filterCounter++
   590  	}
   591  	return filterQuery, params, nil
   592  }