Skip to content

Commit c2e75a0

Browse files
authored
feat: [OCISDEV-285] Add Cli to delete personal spaces (#11701)
* Add Cli to delete personal spaces * fix EnsurePersonalSpace * Purge disabled spaces 'personal' or 'project' * bump reva * update the test
1 parent b785f6d commit c2e75a0

File tree

8 files changed

+25892
-68
lines changed

8 files changed

+25892
-68
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Enhancement: Add Cli to delete personal spaces
2+
3+
Add Cli to delete the trashed personal spaces.
4+
5+
https://github.com/owncloud/ocis/pull/11555

coverage.out

Lines changed: 25554 additions & 0 deletions
Large diffs are not rendered by default.

ocis-pkg/shared/storage_utils.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,6 @@ func EnsurePersonalSpace(ctx context.Context, client gateway.GatewayAPIClient, u
7878
}
7979
return nil
8080
}
81-
if errors.Is(err, ErrNotFound) {
82-
req := &storageprovider.CreateStorageSpaceRequest{
83-
Type: _spaceTypePersonal,
84-
Owner: &userv1beta1.User{Id: &userv1beta1.UserId{OpaqueId: user.GetId()}},
85-
Name: user.GetDisplayName(),
86-
}
87-
cRes, cerr := client.CreateStorageSpace(ctx, req)
88-
if cerr != nil {
89-
return fmt.Errorf("failed to create personal space: %w", cerr)
90-
}
91-
if cRes.GetStatus().GetCode() == cs3rpc.Code_CODE_ALREADY_EXISTS {
92-
return nil
93-
}
94-
if cRes.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
95-
return errorcode.NewFromStatusCode(cRes.GetStatus().GetCode(), cRes.GetStatus().GetMessage())
96-
}
97-
}
9881
return nil
9982
}
10083

ocis-pkg/shared/storage_utils_test.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,35 +72,27 @@ func TestEnsurePersonalSpace(t *testing.T) {
7272
require.NoError(t, err)
7373
})
7474

75-
t.Run("creates when not found", func(t *testing.T) {
75+
t.Run("no-op when not found", func(t *testing.T) {
7676
gw := cs3mocks.NewGatewayAPIClient(t)
7777
gw.EXPECT().ListStorageSpaces(mock.Anything, mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
7878
Status: okStatus(),
7979
StorageSpaces: []*storageprovider.StorageSpace{},
8080
}, nil).Once()
8181

82-
gw.EXPECT().CreateStorageSpace(mock.Anything, mock.Anything, mock.Anything).Return(&storageprovider.CreateStorageSpaceResponse{
83-
Status: okStatus(),
84-
}, nil).Once()
85-
8682
user := libregraph.NewUser("User Three", "user3")
8783
user.SetId("user3")
8884

8985
err := EnsurePersonalSpace(context.Background(), gw, *user)
9086
require.NoError(t, err)
9187
})
9288

93-
t.Run("create returns already exists treated as success", func(t *testing.T) {
89+
t.Run("no-op when not found (empty spaces)", func(t *testing.T) {
9490
gw := cs3mocks.NewGatewayAPIClient(t)
9591
gw.EXPECT().ListStorageSpaces(mock.Anything, mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
9692
Status: okStatus(),
9793
StorageSpaces: []*storageprovider.StorageSpace{},
9894
}, nil).Once()
9995

100-
gw.EXPECT().CreateStorageSpace(mock.Anything, mock.Anything, mock.Anything).Return(&storageprovider.CreateStorageSpaceResponse{
101-
Status: status(cs3rpc.Code_CODE_ALREADY_EXISTS, "exists"),
102-
}, nil).Once()
103-
10496
user := libregraph.NewUser("User Four", "user4")
10597
user.SetId("user4")
10698

services/graph/pkg/service/v0/approleassignments_test.go

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -459,47 +459,6 @@ var _ = Describe("AppRoleAssignments", func() {
459459

460460
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
461461
})
462-
463-
It("returns error when EnsurePersonalSpace fails for non-UserLight role", func() {
464-
userRoleAssignment := &settingsmsg.UserRoleAssignment{
465-
Id: "some-appRoleAssignment-ID",
466-
AccountUuid: "user1",
467-
RoleId: "some-appRole-ID",
468-
}
469-
roleService.On("ListRoleAssignments", mock.Anything, mock.Anything, mock.Anything).Return(&settings.ListRoleAssignmentsResponse{Assignments: []*settingsmsg.UserRoleAssignment{}}, nil)
470-
roleService.On("AssignRoleToUser", mock.Anything, mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{Assignment: userRoleAssignment}, nil)
471-
472-
// Reset the mock and set up the failing scenario
473-
gatewayClient.ExpectedCalls = nil
474-
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userv1beta1.GetUserResponse{
475-
Status: &rpc.Status{Code: rpc.Code_CODE_OK},
476-
User: currentUser,
477-
}, nil)
478-
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&storageprovider.ListStorageSpacesResponse{
479-
Status: &rpc.Status{Code: rpc.Code_CODE_OK},
480-
StorageSpaces: []*storageprovider.StorageSpace{},
481-
}, nil)
482-
gatewayClient.On("CreateStorageSpace", mock.Anything, mock.Anything).Return(&storageprovider.CreateStorageSpaceResponse{
483-
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL, Message: "internal error"},
484-
}, nil)
485-
486-
ara := libregraph.NewAppRoleAssignmentWithDefaults()
487-
ara.SetAppRoleId("some-appRole-ID")
488-
ara.SetPrincipalId("user1")
489-
ara.SetResourceId(cfg.Application.ID)
490-
491-
araJson, err := json.Marshal(ara)
492-
Expect(err).ToNot(HaveOccurred())
493-
494-
r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users/user1/appRoleAssignments", bytes.NewBuffer(araJson))
495-
rctx := chi.NewRouteContext()
496-
rctx.URLParams.Add("userID", "user1")
497-
r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx))
498-
svc.CreateAppRoleAssignment(rr, r)
499-
500-
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
501-
})
502-
503462
})
504463

505464
Describe("DeleteAppRoleAssignment", func() {

services/storage-users/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,55 @@ ocis storage-users uploads sessions --expired=true --clean
140140
ocis storage-users uploads sessions --processing=true --has-virus=false --resume
141141
```
142142

143+
### Manage Spaces
144+
145+
This command set provides commands to manage spaces, including purging disabled spaces that exceed the retention period.
146+
147+
```bash
148+
ocis storage-users spaces <command>
149+
```
150+
151+
```plaintext
152+
COMMANDS:
153+
purge Purge disabled spaces that exceed the retention period
154+
```
155+
156+
#### Purge (delete permanently) Disabled Spaces
157+
158+
Purge disabled spaces of a specific type that have exceeded the retention period. This command helps delete permanently the spaces that have been disabled and are no longer needed.
159+
160+
```bash
161+
ocis storage-users spaces purge [command options]
162+
```
163+
164+
**Options:**
165+
- `--dry-run, -d` - Only show what would be purged without actually purging (default: true)
166+
- `--type, -t` - Type of spaces to purge: 'personal' or 'project' (required)
167+
- `--space-id, -s` - Specific space ID to purge (optional, omit to process all spaces)
168+
- `--retention-period, -r` - Retention period for disabled spaces (default: '336h', e.g., '14d', '720h')
169+
- `--verbose, -v` - Enable verbose logging (default: false)
170+
171+
**Examples:**
172+
173+
```bash
174+
# Dry run to see what would be purged (recommended first step)
175+
ocis storage-users spaces purge --type=personal
176+
177+
# Purge all disabled personal spaces older than 14 days
178+
ocis storage-users spaces purge --type=personal --retention-period=14d --dry-run=false
179+
180+
# Purge a specific project space
181+
ocis storage-users spaces purge --type=project --space-id='f46bae39-b2e4-48c7-a1bc-26169b1ffc2e$2d274464-0d11-4334-9f66-391cbe38c8a5!2d274464-0d11-4334-9f66-391cbe38c8a5' --dry-run=false
182+
183+
# Purge with verbose logging
184+
ocis storage-users spaces purge --type=personal --verbose --dry-run=false
185+
```
186+
187+
**Important Notes:**
188+
- Only processes spaces that are in 'trashed' state
189+
- The `--dry-run` flag defaults to `true` to prevent accidental purging
190+
- Retention period supports human-readable formats (e.g., '336h', '14d', '720h')
191+
143192
### Manage Trash-Bin Items
144193

145194
This command set provides commands to get an overview of trash-bin items, restore items and purge old items of `personal` spaces and `project` spaces (spaces that have been created manually). `trash-bin` commands require a `spaceID` as parameter. See [List all spaces

services/storage-users/pkg/command/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func GetCommands(cfg *config.Config) cli.Commands {
1717
// interaction with this service
1818
Uploads(cfg),
1919
TrashBin(cfg),
20+
Spaces(cfg),
2021

2122
// infos about this service
2223
Health(cfg),

0 commit comments

Comments
 (0)