Skip to content

Commit 6b8c45a

Browse files
committed
ListReceivedShares now uses a JOIN
1 parent d2f446e commit 6b8c45a

File tree

3 files changed

+49
-46
lines changed

3 files changed

+49
-46
lines changed

share/model.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ type PublicLink struct {
6767

6868
type ShareState struct {
6969
gorm.Model
70-
Share Share
70+
ShareID uint `gorm:"foreignKey:ShareID;references:ID"` // Define the foreign key field
71+
Share Share // Define the association
7172
// Can not be uid because of lw accs
7273
User string
7374
Synced bool

share/sql/sql.go

+46-45
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,6 @@ func (m *mgr) isProjectAdmin(u *userpb.User, path string) bool {
319319
if g == adminGroup {
320320
// User belongs to the admin group, list all shares for the resource
321321

322-
// TODO: this only works if shares for a single project are requested.
323-
// If shares for multiple projects are requested, then we're not checking if the
324-
// user is an admin for all of those. We can append the query ` or uid_owner=?`
325-
// for all the project owners, which works fine for new reva
326-
// but won't work for revaold since there, we store the uid of the share creator as uid_owner.
327-
// For this to work across the two versions, this change would have to be made in revaold
328-
// but it won't be straightforward as there, the storage provider doesn't return the
329-
// resource owners.
330322
return true
331323
}
332324
}
@@ -364,65 +356,67 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) (
364356
func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) {
365357
user := appctx.ContextMustGetUser(ctx)
366358

367-
query := m.db.Model(&model.Share{}).
368-
Where("orphan = ?", false)
359+
// We need to do this to parse the result
360+
// Normally, GORM would be able to fill in the Share that is referenced in ShareState
361+
// However, in GORM's docs: "Join Preload will loads association data using left join"
362+
// Because we do a RIGHT JOIN, GORM cannot load the data into shareState.Share (in case that ShareState is empty)
363+
// So we load them both separately, and then set ShareState.Share = Share ourselves
364+
var results []struct {
365+
model.ShareState
366+
model.Share
367+
}
368+
369+
query := m.db.Model(&model.ShareState{}).
370+
Select("share_states.*, shares.*").
371+
Joins("RIGHT OUTER JOIN shares ON shares.id = share_states.share_id").
372+
Where("shares.orphan = ?", false)
369373

370374
// Also search by all the groups the user is a member of
371-
innerQuery := m.db.Where("share_with = ? and shared_with_is_group = ?", user.Username, false)
375+
innerQuery := m.db.Where("shares.share_with = ? and shares.shared_with_is_group = ?", user.Username, false)
372376
for _, group := range user.Groups {
373-
innerQuery = innerQuery.Or("share_with = ? and shared_with_is_group = ?", group, true)
377+
innerQuery = innerQuery.Or("shares.share_with = ? and shares.shared_with_is_group = ?", group, true)
374378
}
375379
query = query.Where(innerQuery)
376380

377381
// Append filters
378382
m.appendFiltersToQuery(query, filters)
379383

380-
// Get the shares
381-
var shares []model.Share
382-
res := query.Find(&shares)
384+
// Get the shares + states
385+
res := query.Find(&results)
383386
if res.Error != nil {
384387
return nil, res.Error
385388
}
386389

387-
// Now that we have the shares, we fetch the share state for every share
388390
var receivedShares []*collaboration.ReceivedShare
389391

390-
for _, s := range shares {
391-
shareId := &collaboration.ShareId{
392-
OpaqueId: strconv.FormatUint(uint64(s.ID), 10),
393-
}
394-
shareState, err := m.getShareState(ctx, shareId, user)
395-
if err != nil {
396-
return nil, err
397-
}
398-
399-
granteeType, _ := m.getUserType(ctx, s.ShareWith)
392+
// Now we parse everything into the CS3 definition of a CS3ReceivedShare
393+
for _, res := range results {
394+
shareState := res.ShareState
395+
shareState.Share = res.Share
396+
granteeType, _ := m.getUserType(ctx, res.Share.ShareWith)
400397

401-
receivedShares = append(receivedShares, s.AsCS3ReceivedShare(shareState, granteeType))
398+
receivedShares = append(receivedShares, res.Share.AsCS3ReceivedShare(&shareState, granteeType))
402399
}
403400

404401
return receivedShares, nil
405402
}
406403

407-
func (m *mgr) getShareState(ctx context.Context, shareId *collaboration.ShareId, user *userpb.User) (*model.ShareState, error) {
404+
// shareId *collaboration.ShareId
405+
func (m *mgr) getShareState(ctx context.Context, share *model.Share, user *userpb.User) (*model.ShareState, error) {
408406
var shareState model.ShareState
409407
query := m.db.Model(&shareState).
410-
Where("share_id = ?", shareId.OpaqueId).
408+
Where("share_id = ?", share.ID).
411409
Where("user = ?", user.Username)
412410

413411
res := query.First(&shareState)
414412

415413
if res.RowsAffected == 0 {
416-
shareIdInt, err := strconv.Atoi(shareId.OpaqueId)
417-
if err != nil {
418-
return nil, errors.New("Failed to fetch shareState, and failed to create one (share_id is not an int)")
419-
}
420414
// If no share state has been created yet, we create it now using these defaults
421415
shareState = model.ShareState{
422-
ShareID: uint(shareIdInt),
423-
Hidden: false,
424-
Synced: false,
425-
User: user.Username,
416+
Share: *share,
417+
Hidden: false,
418+
Synced: false,
419+
User: user.Username,
426420
}
427421
// Does not really matter if it fails, next time the user
428422
// lists his shares this will just be called again
@@ -439,7 +433,7 @@ func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId, gt
439433
return nil, err
440434
}
441435

442-
shareState, err := m.getShareState(ctx, id, user)
436+
shareState, err := m.getShareState(ctx, share, user)
443437
if err != nil {
444438
return nil, err
445439
}
@@ -455,11 +449,7 @@ func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey,
455449
return nil, err
456450
}
457451

458-
shareId := &collaboration.ShareId{
459-
OpaqueId: strconv.Itoa(int(share.ID)),
460-
}
461-
462-
shareState, err := m.getShareState(ctx, shareId, user)
452+
shareState, err := m.getShareState(ctx, share, user)
463453
if err != nil {
464454
return nil, err
465455
}
@@ -496,12 +486,23 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.Rece
496486

497487
user := appctx.ContextMustGetUser(ctx)
498488

499-
rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Share.Id}})
489+
rs, err := m.getReceivedByID(ctx, share.Share.Id, user.Id.Type)
490+
if err != nil {
491+
return nil, err
492+
}
493+
494+
shareId, err := strconv.Atoi(share.Share.Id.OpaqueId)
500495
if err != nil {
501496
return nil, err
502497
}
503498

504-
shareState, err := m.getShareState(ctx, share.Share.Id, user)
499+
shareState, err := m.getShareState(ctx, &model.Share{
500+
ProtoShare: model.ProtoShare{
501+
Model: gorm.Model{
502+
ID: uint(shareId),
503+
},
504+
},
505+
}, user)
505506
if err != nil {
506507
return nil, err
507508
}

share/sql/sql_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ func TestListReceivedShares(t *testing.T) {
363363

364364
if len(receivedShares) != 1 {
365365
t.Errorf("Expected 1 received share, got %d", len(receivedShares))
366+
t.FailNow()
366367
}
367368

368369
if receivedShares[0].Share.Id.OpaqueId != res.Id.OpaqueId {

0 commit comments

Comments
 (0)