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 }