Enhancement: No longer returns shares whose expiration date has passed.#5571
Enhancement: No longer returns shares whose expiration date has passed.#5571pmedinar01 wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds expiration handling for user/group shares by filtering expired shares from received listings, providing a DB query to enumerate expired shares, and introducing a gateway-side cleanup routine to remove expired shares and associated storage grants.
Changes:
- Filter expired shares out of
ListReceivedSharesresults in the SQL share manager. - Add
ListExpiredSharesto fetch all expired (non-orphan, non-deleted) shares from the SQL backend. - Add
ExpireSharesin the gateway to remove storage grants and delete expired shares; add an unreleased changelog entry.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| pkg/share/manager/sql/share.go | Filters expired shares from received listings; adds DB-level listing of expired shares. |
| internal/grpc/services/gateway/usershareprovider.go | Adds an expiration cleanup method that removes grants and deletes expired shares. |
| changelog/unreleased/expire-shares.md | Documents the new expiration behavior and APIs (needs template alignment). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if _, err := c.RemoveShare(ctx, &collaboration.RemoveShareRequest{Ref: ref}); err != nil { | ||
| return errors.Wrap(err, "gateway: error removing expired share "+share.Id.OpaqueId) | ||
| } |
There was a problem hiding this comment.
ExpireShares ignores the RemoveShare response status: it only checks the gRPC error, so a non-OK status could be silently treated as success and leave the expired share in the DB. Capture the response and verify Status.Code == CODE_OK (and include Status.Message in the returned error) similarly to the ListShares and removeGrant checks above.
| if _, err := c.RemoveShare(ctx, &collaboration.RemoveShareRequest{Ref: ref}); err != nil { | |
| return errors.Wrap(err, "gateway: error removing expired share "+share.Id.OpaqueId) | |
| } | |
| removeShareRes, err := c.RemoveShare(ctx, &collaboration.RemoveShareRequest{Ref: ref}) | |
| if err != nil { | |
| return errors.Wrap(err, "gateway: error removing expired share "+share.Id.OpaqueId) | |
| } | |
| if removeShareRes.Status.Code != rpc.Code_CODE_OK { | |
| return fmt.Errorf("gateway: RemoveShare failed for share %s: %s", share.Id.OpaqueId, removeShareRes.Status.Message) | |
| } |
| // ListExpiredShares returns all non-deleted, non-orphan shares whose expiration date is in the past. | ||
| func (m *ShareMgr) ListExpiredShares(ctx context.Context) ([]*collaboration.Share, error) { | ||
| var modelShares []model.Share | ||
| res := m.db.Model(&model.Share{}). | ||
| Where("orphan = ?", false). | ||
| Where("deleted_at IS NULL"). | ||
| Where("expiration IS NOT NULL AND expiration < ?", time.Now()). | ||
| Find(&modelShares) | ||
| if res.Error != nil { | ||
| return nil, res.Error | ||
| } | ||
|
|
||
| shares := make([]*collaboration.Share, 0, len(modelShares)) | ||
| for _, s := range modelShares { | ||
| granteeType, _ := m.getUserType(ctx, s.ShareWith) | ||
| shares = append(shares, s.AsCS3Share(granteeType)) | ||
| } | ||
| return shares, nil |
There was a problem hiding this comment.
ListExpiredShares adds new behavior (querying and returning all expired shares) but there is no test coverage for it in the existing SQL share manager test suite (share_test.go). Please add tests that create shares with past and future expirations and verify only the past-expired ones are returned.
| - `ListReceivedShares` no longer returns shares whose expiration date has passed | ||
| - New `ListExpiredShares` method on the SQL share manager returns all shares past their expiry | ||
| - New `ExpireShares` method on the gateway removes storage grants and deletes all expired shares |
There was a problem hiding this comment.
This changelog entry does not follow changelog/TEMPLATE: it uses a bullet list and is missing the trailing section with issue/PR URLs that the changelog tooling expects. Please adjust the body to match the template format (paragraphs in past tense) and add the relevant PR/issue link(s) at the end.
| - `ListReceivedShares` no longer returns shares whose expiration date has passed | |
| - New `ListExpiredShares` method on the SQL share manager returns all shares past their expiry | |
| - New `ExpireShares` method on the gateway removes storage grants and deletes all expired shares | |
| `ListReceivedShares` no longer returned shares whose expiration date had passed. A new `ListExpiredShares` method on the SQL share manager returned all shares past their expiry. A new `ExpireShares` method on the gateway removed storage grants and deleted all expired shares. | |
| Issues: | |
| - https://github.com/<owner>/<repo>/issues/<number> | |
| - https://github.com/<owner>/<repo>/pull/<number> |
| @@ -236,7 +236,8 @@ func (m *ShareMgr) ListReceivedShares(ctx context.Context, filters []*collaborat | |||
| Select("share_states.*, shares.*"). | |||
| Joins("RIGHT OUTER JOIN shares ON shares.id = share_states.share_id and share_states.user = ?", user.Username). | |||
| Where("shares.orphan = ?", false). | |||
| Where("shares.deleted_at IS NULL") | |||
| Where("shares.deleted_at IS NULL"). | |||
| Where("shares.expiration IS NULL OR shares.expiration > ?", time.Now()) | |||
There was a problem hiding this comment.
Expiration is only enforced in ListReceivedShares (via the SQL shares.expiration predicate). Other read paths like GetReceivedShare/GetShare ultimately call getShareByID/getShareByKey, which do not check expiration, so an expired share can still be fetched by reference until a cleanup job removes it. If expiration is meant to revoke access immediately, consider applying the same expiration constraint in the lower-level getShare... queries (or returning NotFound for expired shares).
522e906 to
88afb6c
Compare
3a226c7 to
be1e421
Compare
No description provided.