Skip to content

Commit 80d7c90

Browse files
Merge pull request #109 from smar-brian-keare/bkeare/workspaces_folders
Deprecate and replace workspace and folder endpoints
2 parents a0ec65d + 645f7ce commit 80d7c90

24 files changed

+1347
-201
lines changed

CHANGELOG.md

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,25 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66
## [Unreleased]
77

8-
## [5.1.0] - 2025-08-12
8+
## [5.1.0] - 2025-08-25
99
### Added
1010
- Add support for token-based pagination in WorkspaceResources.ListWorkspaces()
1111
- New TokenPaginationParameters class to support paginationType, lastKey and maxItems parameters
1212
- New TokenPaginatedResult<T> class for token-based pagination responses with data and lastKey properties
13+
- GetWorkspaceChildren endpoint with support for token-based pagination
14+
- GetWorkspaceMetadata endpoint with support for numericDates and accessApiLevel parameters
15+
- GetFolderChildren endpoint with support for token-based pagination
16+
- GetFolderMetadata endpoint with support for numericDates parameter
17+
18+
### Changed
19+
- Updated Folder model with CreatedAt and ModifiedAt properties supporting both DateTime and Long values
20+
21+
### Deprecated
22+
- GetFolder method in FolderResources (use GetFolderChildren and GetFolderMetadata instead)
23+
- GetWorkspace method in WorkspaceResources (use GetWorkspaceChildren and GetWorkspaceMetadata instead)
24+
- ListFolders method in FolderResources (use GetFolderChildren instead)
25+
- ListFolders method in WorkspaceFolderResources (use GetWorkspaceChildren instead)
26+
- HomeFolderResources interface and all its methods (See the API docs article on [migrating off the Sheets folder](https://developers.smartsheet.com/api/smartsheet/guides/updating-code/migrate-from-using-the-sheets-folder))
1327

1428
## [3.0.0] - 2022-12-07
1529
### Updated
@@ -36,16 +50,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
3650
- [Unable to Search Sheet Summary #117](https://github.com/smartsheet-platform/smartsheet-csharp-sdk/issues/117)
3751

3852
## [2.93.0] - 2020-03-12
39-
### Added
53+
### Added
4054
- Webhooks for columns support
4155

42-
### Fixed
56+
### Fixed
4357
- [Json deserialization error #113](https://github.com/smartsheet-platform/smartsheet-csharp-sdk/issues/113)
4458

4559
### Changed
46-
- disable Newtonsoft default configuration of deserializing strings that "look like" dates into C# DateTime objects,
47-
see [README](https://github.com/smartsheet-platform/smartsheet-csharp-sdk/blob/master/README.md) for details on how
48-
to opt-out of this change if required.
60+
- disable Newtonsoft default configuration of deserializing strings that "look like" dates into C# DateTime objects,
61+
see [README](https://github.com/smartsheet-platform/smartsheet-csharp-sdk/blob/master/README.md) for details on how
62+
to opt-out of this change if required.
4963

5064
## [2.86.0] - 2019-11-07
5165
### Added
@@ -64,7 +78,7 @@ to opt-out of this change if required.
6478
- continue to support level 0 widget types
6579

6680
## [2.77.0] - 2019-07-25
67-
### Added
81+
### Added
6882
- CARD_DONE tag to column tags enumeration
6983
- `Description` property to Column model
7084
- ListUsers accepts an `includes` parameter - the only currently accepted argument value is `LAST_LOGIN`
@@ -83,7 +97,7 @@ to opt-out of this change if required.
8397

8498
## [2.68.2] - 2019-05-29
8599
### Added
86-
- Support for .NET Standard 2.0. Nuget.org package contains assemblies for both .NET Framework 4.5.2 and
100+
- Support for .NET Standard 2.0. Nuget.org package contains assemblies for both .NET Framework 4.5.2 and
87101
.NET Standard 2.0.
88102

89103
## [2.68.1] - 2019-05-15
@@ -127,7 +141,7 @@ to opt-out of this change if required.
127141
- Row sort feature
128142
- User profile properties (including profileImage) to UserModel
129143
- Scope, location, and favoriteFlag inclusion to search
130-
- getSheet() ifVersionAfter parameter
144+
- getSheet() ifVersionAfter parameter
131145
- Expose Change-Agent, Assumed-User, and User-Agent on Smartsheet client
132146
- Bulk access to sheet version through sheetVersion inclusion
133147
- Missing report and sheet publish flags
@@ -138,10 +152,10 @@ to opt-out of this change if required.
138152

139153
### Changed
140154
- Implementation of objectValue to better support PredecessorList and objectValue primitives (examples of how to set and clear Predecessor list can be found in the `RowTests.cs` mock tests)
141-
- HttpClient interface to allow SDK users to inject HTTP headers or implement an HTTP proxy by extending
155+
- HttpClient interface to allow SDK users to inject HTTP headers or implement an HTTP proxy by extending
142156
DefaultHttpClient (a proxy sample is provided in the Advanced Topics section of the README)
143157
- Removed outdated Link model and replaced all references with current Hyperlink model
144-
- Removed ShouldRetry and CalcBackoff interfaces and replaced with HttpClient interface methods. You can now customize
158+
- Removed ShouldRetry and CalcBackoff interfaces and replaced with HttpClient interface methods. You can now customize
145159
shouldRetry or calcBackoff using the same method as proxy or request header injection (i.e., extend DefaultHttpClient).
146160

147161
### Fixed

integration-test-sdk-net80/WorkspaceResourcesTest.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class WorkspaceResourcesTest
1010
public void TestWorkspaceResources()
1111
{
1212
SmartsheetClient smartsheet = new SmartsheetBuilder().SetMaxRetryTimeout(30000).Build();
13-
13+
1414
long workspaceId = CreateWorkspace(smartsheet);
1515

1616
UpdateWorkspace(smartsheet, workspaceId);
@@ -48,62 +48,62 @@ private static void ListWorkspaces(SmartsheetClient smartsheet, long workspaceId
4848
private static void ListWorkspacesWithTokenPagination(SmartsheetClient smartsheet, long workspaceId)
4949
{
5050
// Test token-based pagination with maxItems parameter
51-
TokenPaginationParameters tokenPaging = new TokenPaginationParameters(null, 100);
51+
ListWorkspacesTokenPaginationParameters tokenPaging = new ListWorkspacesTokenPaginationParameters(null, 100);
5252
TokenPaginatedResult<Workspace> workspaceResult = smartsheet.WorkspaceResources.ListWorkspaces(tokenPaging);
53-
53+
5454
Assert.IsNotNull(workspaceResult);
5555
Assert.IsNotNull(workspaceResult.Data);
5656
Assert.IsTrue(workspaceResult.Data.Count > 0);
5757

5858
// Test token-based pagination with explicit paginationType parameter
59-
TokenPaginationParameters tokenPagingWithType = new TokenPaginationParameters(null, 100, "token");
59+
ListWorkspacesTokenPaginationParameters tokenPagingWithType = new ListWorkspacesTokenPaginationParameters(null, 100, "token");
6060
TokenPaginatedResult<Workspace> workspaceResultWithType = smartsheet.WorkspaceResources.ListWorkspaces(tokenPagingWithType);
6161
Assert.IsNotNull(workspaceResultWithType);
6262
Assert.IsNotNull(workspaceResultWithType.Data);
6363
Assert.IsTrue(workspaceResultWithType.Data.Count > 0);
6464
Assert.AreEqual("token", tokenPagingWithType.PaginationType);
6565

6666
// Test token-based pagination without parameters (should get default results)
67-
TokenPaginatedResult<Workspace> workspaceResultNoPaging = smartsheet.WorkspaceResources.ListWorkspaces((TokenPaginationParameters?)null);
67+
TokenPaginatedResult<Workspace> workspaceResultNoPaging = smartsheet.WorkspaceResources.ListWorkspaces((ListWorkspacesTokenPaginationParameters?)null);
6868
Assert.IsNotNull(workspaceResultNoPaging);
6969
Assert.IsNotNull(workspaceResultNoPaging.Data);
7070
Assert.IsTrue(workspaceResultNoPaging.Data.Count > 0);
7171

7272
// Test lastKey functionality for token pagination
7373
// First page with small maxItems to ensure pagination occurs
74-
TokenPaginationParameters firstPageParams = new TokenPaginationParameters(null, 100);
74+
ListWorkspacesTokenPaginationParameters firstPageParams = new ListWorkspacesTokenPaginationParameters(null, 100);
7575
TokenPaginatedResult<Workspace> firstPageResult = smartsheet.WorkspaceResources.ListWorkspaces(firstPageParams);
76-
76+
7777
Assert.IsNotNull(firstPageResult);
7878
Assert.IsNotNull(firstPageResult.Data);
7979
Assert.IsTrue(firstPageResult.Data.Count > 0);
80-
80+
8181
// If there are more workspaces, there should be a lastKey for the next page
8282
if (firstPageResult.LastKey != null)
8383
{
8484
// Second page using the lastKey from the first page
85-
TokenPaginationParameters secondPageParams = new TokenPaginationParameters(firstPageResult.LastKey, 100);
85+
ListWorkspacesTokenPaginationParameters secondPageParams = new ListWorkspacesTokenPaginationParameters(firstPageResult.LastKey, 100);
8686
TokenPaginatedResult<Workspace> secondPageResult = smartsheet.WorkspaceResources.ListWorkspaces(secondPageParams);
87-
87+
8888
Assert.IsNotNull(secondPageResult);
8989
Assert.IsNotNull(secondPageResult.Data);
90-
90+
9191
// Verify that the second page returns different data (if available)
9292
if (secondPageResult.Data.Count > 0 && firstPageResult.Data.Count > 0)
9393
{
9494
// The first workspace from page 1 should be different from the first workspace from page 2
95-
Assert.AreNotEqual(firstPageResult.Data[0].Id, secondPageResult.Data[0].Id,
95+
Assert.AreNotEqual(firstPageResult.Data[0].Id, secondPageResult.Data[0].Id,
9696
"Second page should return different workspaces than first page");
9797
}
9898
}
9999

100100
// Test that maxItems=1 generates an error from Smartsheet API
101101
SmartsheetException exception = Assert.ThrowsException<SmartsheetException>(() =>
102102
{
103-
TokenPaginationParameters invalidParams = new TokenPaginationParameters(null, 1);
103+
ListWorkspacesTokenPaginationParameters invalidParams = new ListWorkspacesTokenPaginationParameters(null, 1);
104104
smartsheet.WorkspaceResources.ListWorkspaces(invalidParams);
105105
});
106-
106+
107107
Assert.IsNotNull(exception.Message, "Exception should have a message");
108108
}
109109

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Smartsheet.Api;
3+
using Smartsheet.Api.Models;
4+
using System.Linq;
5+
6+
namespace mock_api_test_sdk_net80
7+
{
8+
[TestClass]
9+
public class FolderTests
10+
{
11+
[TestMethod]
12+
public void GetFolderChildren_NoParams()
13+
{
14+
SmartsheetClient ss = HelperFunctions.SetupClient("Get Folder Children - No Params");
15+
16+
// No params - use minimal required parameters
17+
TokenPaginatedResult<object> children = ss.FolderResources.GetFolderChildren(456);
18+
19+
Assert.IsNotNull(children);
20+
Assert.IsNotNull(children.Data);
21+
Assert.AreEqual(4, children.Data.Count);
22+
23+
// Find specific items by ID and validate their properties using proper model classes
24+
var childrenList = children.Data.ToList();
25+
26+
// Subfolder (id: 987)
27+
var subfolder = childrenList.FirstOrDefault(c => GetItemId(c) == 987) as Folder;
28+
Assert.IsNotNull(subfolder);
29+
Assert.AreEqual("Subfolder", subfolder.Name);
30+
31+
// Task List (id: 234)
32+
var taskList = childrenList.FirstOrDefault(c => GetItemId(c) == 234) as Sheet;
33+
Assert.IsNotNull(taskList);
34+
Assert.AreEqual("Task List", taskList.Name);
35+
Assert.AreEqual(AccessLevel.EDITOR, taskList.AccessLevel);
36+
37+
// Project Dashboard (id: 567)
38+
var projectDashboard = childrenList.FirstOrDefault(c => GetItemId(c) == 567) as Sight;
39+
Assert.IsNotNull(projectDashboard);
40+
Assert.AreEqual("Project Dashboard", projectDashboard.Name);
41+
Assert.AreEqual(AccessLevel.EDITOR, projectDashboard.AccessLevel);
42+
43+
// Status Report (id: 890)
44+
var statusReport = childrenList.FirstOrDefault(c => GetItemId(c) == 890) as Report;
45+
Assert.IsNotNull(statusReport);
46+
Assert.AreEqual("Status Report", statusReport.Name);
47+
Assert.AreEqual(AccessLevel.VIEWER, statusReport.AccessLevel);
48+
}
49+
50+
[TestMethod]
51+
public void GetFolderChildren_IncludeSourceAndOwnerInfo()
52+
{
53+
SmartsheetClient ss = HelperFunctions.SetupClient("Get Folder Children - Include Source and OwnerInfo");
54+
55+
// Include source and owner info as specified in scenario title
56+
TokenPaginatedResult<object> children = ss.FolderResources.GetFolderChildren(
57+
456,
58+
null,
59+
new List<ChildrenInclusion> { ChildrenInclusion.SOURCE, ChildrenInclusion.OWNER_INFO }
60+
);
61+
62+
Assert.IsNotNull(children);
63+
Assert.IsNotNull(children.Data);
64+
Assert.AreEqual(4, children.Data.Count);
65+
66+
// Verify specific source values for each child using proper model classes
67+
foreach (var item in children.Data)
68+
{
69+
var itemId = GetItemId(item);
70+
71+
// Assert specific source values based on the expected response
72+
switch (itemId)
73+
{
74+
case 987: // Subfolder
75+
var subfolder = item as Folder;
76+
Assert.IsNotNull(subfolder);
77+
Assert.IsNotNull(subfolder.Source);
78+
Assert.AreEqual(444L, subfolder.Source.Id);
79+
Assert.AreEqual("folder", subfolder.Source.Type);
80+
break;
81+
case 234: // Task List
82+
var taskList = item as Sheet;
83+
Assert.IsNotNull(taskList);
84+
Assert.IsNotNull(taskList.Source);
85+
Assert.AreEqual(333L, taskList.Source.Id);
86+
Assert.AreEqual("sheet", taskList.Source.Type);
87+
// Verify owner info for sheet
88+
Assert.AreEqual("[email protected]", taskList.Owner);
89+
Assert.AreEqual(2002L, taskList.OwnerId);
90+
break;
91+
case 567: // Project Dashboard
92+
var projectDashboard = item as Sight;
93+
Assert.IsNotNull(projectDashboard);
94+
Assert.IsNotNull(projectDashboard.Source);
95+
Assert.AreEqual(222L, projectDashboard.Source.Id);
96+
Assert.AreEqual("sight", projectDashboard.Source.Type);
97+
break;
98+
case 890: // Status Report
99+
var statusReport = item as Report;
100+
Assert.IsNotNull(statusReport);
101+
Assert.IsNotNull(statusReport.Source);
102+
Assert.AreEqual(111L, statusReport.Source.Id);
103+
Assert.AreEqual("report", statusReport.Source.Type);
104+
break;
105+
}
106+
}
107+
}
108+
109+
[TestMethod]
110+
public void GetFolderChildren_FilterSightsAndReports()
111+
{
112+
SmartsheetClient ss = HelperFunctions.SetupClient("Get Folder Children - Filter Sights and Reports");
113+
114+
// Filter to only sights and reports as specified in scenario title
115+
TokenPaginatedResult<object> children = ss.FolderResources.GetFolderChildren(
116+
456,
117+
new List<ChildrenResourceType> { ChildrenResourceType.REPORTS, ChildrenResourceType.SIGHTS }
118+
);
119+
120+
Assert.IsNotNull(children);
121+
Assert.IsNotNull(children.Data);
122+
Assert.AreEqual(3, children.Data.Count);
123+
124+
// Verify the returned items using proper model classes
125+
var childrenList = children.Data.ToList();
126+
127+
// Project Dashboard (id: 567)
128+
var projectDashboard = childrenList.FirstOrDefault(c => GetItemId(c) == 567) as Sight;
129+
Assert.IsNotNull(projectDashboard);
130+
Assert.AreEqual("Project Dashboard", projectDashboard.Name);
131+
Assert.AreEqual(AccessLevel.EDITOR, projectDashboard.AccessLevel);
132+
133+
// Status Report (id: 890)
134+
var statusReport = childrenList.FirstOrDefault(c => GetItemId(c) == 890) as Report;
135+
Assert.IsNotNull(statusReport);
136+
Assert.AreEqual("Status Report", statusReport.Name);
137+
Assert.AreEqual(AccessLevel.VIEWER, statusReport.AccessLevel);
138+
139+
// Executive Summary (id: 1567)
140+
var executiveSummary = childrenList.FirstOrDefault(c => GetItemId(c) == 1567) as Sight;
141+
Assert.IsNotNull(executiveSummary);
142+
Assert.AreEqual("Executive Summary", executiveSummary.Name);
143+
Assert.AreEqual(AccessLevel.VIEWER, executiveSummary.AccessLevel);
144+
145+
// Verify only sights and reports are returned (no folders or sheets)
146+
Assert.IsTrue(childrenList.All(item => item is Sight || item is Report));
147+
}
148+
149+
[TestMethod]
150+
public void GetFolderMetadata_NoParams()
151+
{
152+
SmartsheetClient ss = HelperFunctions.SetupClient("Get Folder Metadata - No Params");
153+
154+
// No params - use minimal required parameters
155+
Folder folder = ss.FolderResources.GetFolderMetadata(456);
156+
157+
Assert.IsNotNull(folder);
158+
Assert.AreEqual(456, folder.Id);
159+
Assert.AreEqual("Project Folder", folder.Name);
160+
Assert.AreEqual("https://app.smartsheet.com/b/home?lx=*****************", folder.Permalink);
161+
Assert.IsNotNull(folder.CreatedAt);
162+
Assert.IsNotNull(folder.ModifiedAt);
163+
}
164+
165+
[TestMethod]
166+
public void GetFolderMetadata_IncludeSource()
167+
{
168+
SmartsheetClient ss = HelperFunctions.SetupClient("Get Folder Metadata - Include Source");
169+
170+
// Include source as specified in scenario title
171+
Folder folder = ss.FolderResources.GetFolderMetadata(
172+
456,
173+
new List<FolderInclusion> { FolderInclusion.SOURCE }
174+
);
175+
176+
Assert.IsNotNull(folder);
177+
Assert.AreEqual(456, folder.Id);
178+
Assert.AreEqual("Project Folder", folder.Name);
179+
Assert.IsNotNull(folder.Source);
180+
Assert.AreEqual(888, folder.Source.Id);
181+
Assert.AreEqual("folder", folder.Source.Type);
182+
}
183+
184+
/// <summary>
185+
/// Helper method to get the ID from any model object
186+
/// </summary>
187+
private long GetItemId(object item)
188+
{
189+
if (item is NamedModel namedModel)
190+
{
191+
return namedModel.Id ?? 0;
192+
}
193+
return 0;
194+
}
195+
}
196+
}

0 commit comments

Comments
 (0)