diff --git a/.github/workflows/staging-tests.yml b/.github/workflows/staging-tests.yml new file mode 100644 index 0000000..f008ded --- /dev/null +++ b/.github/workflows/staging-tests.yml @@ -0,0 +1,42 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Dart run tests when activity on staging + +on: + push: + branches: [ "staging" ] + pull_request: + branches: [ "staging" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + # Note: This workflow uses the latest stable version of the Dart SDK. + # You can specify other versions if desired, see documentation here: + # https://github.com/dart-lang/setup-dart/blob/main/README.md + # - uses: dart-lang/setup-dart@v1 + - uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603 + + - name: Install dependencies + run: dart pub get + + # Uncomment this step to verify the use of 'dart format' on each commit. + # - name: Verify formatting + # run: dart format --output=none --set-exit-if-changed . + + # Consider passing '--fatal-infos' for slightly stricter analysis. + - name: Analyze project source + run: dart analyze + + # Your project will need to have tests in test/ and a dependency on + # package:test for this step to succeed. Note that Flutter projects will + # want to change this to 'flutter test'. + - name: Run tests + run: dart test diff --git a/CHANGELOG.md b/CHANGELOG.md index ea68fb9..24a9109 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ +## 0.4.0 + +- Implemented endpoints for Goals, Guests and Task Checklists + +## 0.3.2 + +- Refactoring and minor fixes. + +## 0.3.0 + +- Implemented endpoints for Tasks. + +## 0.2.0 + +- Tests added. +- Implemented endpoints for Attachments, Authentication, Comments, Custom Fields and Folders +- Classes for all api endpoints. + ## 0.1.0 - Initial version. - Added basic functionality -- Wraps all api endpoints. +- Classes for all api endpoints. diff --git a/README.md b/README.md index d5495a5..75a9ecc 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,7 @@ and the Flutter guide for --> -![readmeheaderblack](https://user-images.githubusercontent.com/68122318/216693931-64f1b1a5-d69a-4af4-9f67-ab281bd68c3d.png#gh-light-mode-only) -![readmeheaderwhite](https://user-images.githubusercontent.com/68122318/216693937-2cbf9f31-d643-4457-941e-ba33ba3b638d.png#gh-dark-mode-only) - - -This is an API wrapper for ClickUp +This is a SDK for ClickUp written in Dart ## Features diff --git a/example/clickup_dart_example.dart b/example/clickup_dart_sdk_example.dart similarity index 74% rename from example/clickup_dart_example.dart rename to example/clickup_dart_sdk_example.dart index ae23eb4..c49b1b9 100644 --- a/example/clickup_dart_example.dart +++ b/example/clickup_dart_sdk_example.dart @@ -1,4 +1,4 @@ -import 'package:clickup_dart/clickup_dart_sdk.dart'; +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; void main() async { final token = "pk_testrandomtoken123"; @@ -11,6 +11,7 @@ void main() async { taskID: "8669e046h", useCustomTaskID: false, filePath: "./test/beksinski_sample.jpg"); - print(attachment); + final listComments = await clickUp.comments.getListComments(listID: 1); + print(listComments); } diff --git a/lib/src/auth/auth.dart b/lib/src/auth/auth.dart deleted file mode 100644 index 421978a..0000000 --- a/lib/src/auth/auth.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart'; - -class ClickUpAuth { - late String endPoint; - late String authToken; - - ClickUpAuth({required this.endPoint, required this.authToken}); - - /// Get access token based on your credentials. - Future getAccessToken( - {required String clientID, - required String clientSecret, - required String code}) async { - try { - final response = await post(Uri.parse( - "$endPoint/oauth/token?client_id=$clientID&client_secret=$clientSecret&code=$code")); - print(response.body); - return response.body; - } catch (e) { - print(e.toString()); - return e.toString(); - } - } - - /// Get the user bound to the token. - Future> getAuthorizedUser() async { - try { - final response = await get(Uri.parse("$endPoint/user"), - headers: {"Authorization": authToken}); - final user = jsonDecode(response.body); - return user; - } catch (e) { - print(e.toString()); - return {"error": "$e"}; - } - } - - /// Get the teams bound to authorized user. - Future> getAuthorizedTeams() async { - try { - final response = await get(Uri.parse("$endPoint/team"), - headers: {"Authorization": authToken}); - final teams = jsonDecode(response.body); - return teams; - } catch (e) { - print(e.toString()); - return {"error": "$e"}; - } - } -} diff --git a/lib/src/checklists/checklists.dart b/lib/src/checklists/checklists.dart deleted file mode 100644 index 59b821d..0000000 --- a/lib/src/checklists/checklists.dart +++ /dev/null @@ -1,5 +0,0 @@ -class ClickUpChecklists { - late String endPoint; - late String authToken; - ClickUpChecklists({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/clickup_dart_base.dart b/lib/src/clickup_dart_base.dart index 71e7324..e7efb4f 100644 --- a/lib/src/clickup_dart_base.dart +++ b/lib/src/clickup_dart_base.dart @@ -1,36 +1,37 @@ -import 'package:clickup_dart/src/attachments/attachments.dart'; -import 'package:clickup_dart/src/auth/auth.dart'; -import 'package:clickup_dart/src/checklists/checklists.dart'; -import 'package:clickup_dart/src/comments/comments.dart'; -import 'package:clickup_dart/src/custom_fields/custom_fields.dart'; -import 'package:clickup_dart/src/dependencies/dependencies.dart'; -import 'package:clickup_dart/src/folders/folders.dart'; -import 'package:clickup_dart/src/goals/goals.dart'; -import 'package:clickup_dart/src/guests/guests.dart'; -import 'package:clickup_dart/src/lists/lists.dart'; -import 'package:clickup_dart/src/members/members.dart'; -import 'package:clickup_dart/src/roles/roles.dart'; -import 'package:clickup_dart/src/shared_hierarchy/shared_hierarchy.dart'; -import 'package:clickup_dart/src/spaces/spaces.dart'; -import 'package:clickup_dart/src/tags/tags.dart'; -import 'package:clickup_dart/src/tasks/task_templates.dart'; -import 'package:clickup_dart/src/tasks/tasks.dart'; -import 'package:clickup_dart/src/teams/teams.dart'; -import 'package:clickup_dart/src/time_tracking/time_tracking_legacy.dart'; -import 'package:clickup_dart/src/time_tracking/time_tracking_v2.dart'; -import 'package:clickup_dart/src/users/users.dart'; -import 'package:clickup_dart/src/views/views.dart'; -import 'package:clickup_dart/src/webhooks/webhooks.dart'; +import 'package:http/http.dart'; + +import 'core/endpoints/attachments.dart'; +import 'core/endpoints/auth.dart'; +import 'core/endpoints/task_checklists.dart'; +import 'core/endpoints/comments.dart'; +import 'core/endpoints/custom_fields.dart'; +import 'core/endpoints/task_relationships.dart'; +import 'core/endpoints/folders.dart'; +import 'core/endpoints/goals.dart'; +import 'core/endpoints/guests.dart'; +import 'core/endpoints/lists.dart'; +import 'core/endpoints/members.dart'; +import 'core/endpoints/roles.dart'; +import 'core/endpoints/shared_hierarchy.dart'; +import 'core/endpoints/spaces.dart'; +import 'core/endpoints/tags.dart'; +import 'core/endpoints/task_templates.dart'; +import 'core/endpoints/tasks.dart'; +import 'core/endpoints/teams.dart'; +import 'core/endpoints/time_tracking_legacy.dart'; +import 'core/endpoints/time_tracking_v2.dart'; +import 'core/endpoints/users.dart'; +import 'core/endpoints/views.dart'; +import 'core/endpoints/webhooks.dart'; class ClickUp { late final String apiEndpoint; + late final Client httpClient; late final ClickUpAuth auth; late final ClickUpAttachments attachments; - late final ClickUpChecklists checklists; late final ClickUpComments comments; late final ClickUpCustomFields customFields; - late final ClickUpDependencies dependencies; late final ClickUpFolders folders; late final ClickUpGoals goals; late final ClickUpGuests guests; @@ -41,6 +42,8 @@ class ClickUp { late final ClickUpSpaces spaces; late final ClickUpTags tags; late final ClickUpTasks tasks; + late final ClickUpTaskRelationships taskRelationships; + late final ClickUpTaskChecklists taskChecklists; late final ClickUpTaskTemplates taskTemplates; late final ClickUpTeams teams; late final ClickUpTimeTrackingLegacy timeTrackingLegacy; @@ -54,39 +57,31 @@ class ClickUp { }); void initialize({required String authToken}) async { - auth = ClickUpAuth(endPoint: apiEndpoint, authToken: authToken); - attachments = - ClickUpAttachments(endPoint: apiEndpoint, authToken: auth.authToken); - checklists = - ClickUpChecklists(endPoint: apiEndpoint, authToken: auth.authToken); - comments = - ClickUpComments(endPoint: apiEndpoint, authToken: auth.authToken); - customFields = - ClickUpCustomFields(endPoint: apiEndpoint, authToken: auth.authToken); - dependencies = - ClickUpDependencies(endPoint: apiEndpoint, authToken: auth.authToken); - folders = ClickUpFolders(endPoint: apiEndpoint, authToken: auth.authToken); - goals = ClickUpGoals(endPoint: apiEndpoint, authToken: auth.authToken); - guests = ClickUpGuests(endPoint: apiEndpoint, authToken: auth.authToken); - lists = ClickUpLists(endPoint: apiEndpoint, authToken: auth.authToken); - members = ClickUpMembers(endPoint: apiEndpoint, authToken: auth.authToken); - roles = ClickUpRoles(endPoint: apiEndpoint, authToken: auth.authToken); - sharedHierarchy = ClickUpSharedHierarchy( - endPoint: apiEndpoint, authToken: auth.authToken); - spaces = ClickUpSpaces(endPoint: apiEndpoint, authToken: auth.authToken); - tags = ClickUpTags(endPoint: apiEndpoint, authToken: auth.authToken); - tasks = ClickUpTasks(endPoint: apiEndpoint, authToken: auth.authToken); - taskTemplates = - ClickUpTaskTemplates(endPoint: apiEndpoint, authToken: auth.authToken); - teams = ClickUpTeams(endPoint: apiEndpoint, authToken: auth.authToken); - timeTrackingLegacy = ClickUpTimeTrackingLegacy( - endPoint: apiEndpoint, authToken: auth.authToken); - timeTrackingV2 = - ClickUpTimeTrackingV2(endPoint: apiEndpoint, authToken: auth.authToken); - users = ClickUpUsers(endPoint: apiEndpoint, authToken: auth.authToken); - views = ClickUpViews(endPoint: apiEndpoint, authToken: auth.authToken); - webhooks = - ClickUpWebhooks(endPoint: apiEndpoint, authToken: auth.authToken); + httpClient = Client(); + + auth = ClickUpAuth(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + attachments = ClickUpAttachments(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + comments = ClickUpComments(endPoint: apiEndpoint, authToken: auth.authToken, httpClient: httpClient); + customFields = ClickUpCustomFields(endPoint: apiEndpoint, authToken: auth.authToken, httpClient: httpClient); + folders = ClickUpFolders(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + goals = ClickUpGoals(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + guests = ClickUpGuests(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + lists = ClickUpLists(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + members = ClickUpMembers(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + roles = ClickUpRoles(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + sharedHierarchy = ClickUpSharedHierarchy(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + spaces = ClickUpSpaces(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + tags = ClickUpTags(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + tasks = ClickUpTasks(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + taskChecklists = ClickUpTaskChecklists(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + taskRelationships = ClickUpTaskRelationships(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + taskTemplates = ClickUpTaskTemplates(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + teams = ClickUpTeams(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + timeTrackingLegacy = ClickUpTimeTrackingLegacy(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + timeTrackingV2 = ClickUpTimeTrackingV2(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + users = ClickUpUsers(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + views = ClickUpViews(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); + webhooks = ClickUpWebhooks(endPoint: apiEndpoint, authToken: authToken, httpClient: httpClient); print("ClickUp Initialized.."); } } diff --git a/lib/src/comments/comments.dart b/lib/src/comments/comments.dart deleted file mode 100644 index 0c94422..0000000 --- a/lib/src/comments/comments.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'dart:convert'; - -import 'package:http/http.dart'; - -class ClickUpComments { - late String endPoint; - late String authToken; - ClickUpComments({required this.endPoint, required this.authToken}); - - Future> getTaskComments({ - required String taskID, - bool useCustomTaskID = false, - int? teamID, - int? start, - String? startID, - }) async { - try { - final response = await get(Uri.parse("$endPoint/task/$taskID/comment"), - headers: {"Authorization": authToken}); - final comments = jsonDecode(response.body); - return comments; - } catch (e) { - print(e.toString()); - return {"error": "$e"}; - } - } -} diff --git a/lib/src/core/clickup_exception.dart b/lib/src/core/clickup_exception.dart new file mode 100644 index 0000000..f209b7f --- /dev/null +++ b/lib/src/core/clickup_exception.dart @@ -0,0 +1,9 @@ +enum ClickUpExceptionType { invalidModel, requestError, unauthorized } + +class ClickUpException implements Exception { + ClickUpException( + {required this.exceptionType, required this.exceptionMessage}); + + final ClickUpExceptionType exceptionType; + final String exceptionMessage; +} diff --git a/lib/src/attachments/attachments.dart b/lib/src/core/endpoints/attachments.dart similarity index 69% rename from lib/src/attachments/attachments.dart rename to lib/src/core/endpoints/attachments.dart index b54a94e..9c17246 100644 --- a/lib/src/attachments/attachments.dart +++ b/lib/src/core/endpoints/attachments.dart @@ -1,11 +1,16 @@ import 'dart:convert'; - import 'package:http/http.dart'; +import '../clickup_exception.dart'; + class ClickUpAttachments { - ClickUpAttachments({required this.endPoint, required this.authToken}); + ClickUpAttachments( + {required this.endPoint, + required this.authToken, + required this.httpClient}); final String endPoint; final String authToken; + late Client httpClient; Future> createTaskAttachment({ required String taskID, @@ -26,7 +31,10 @@ class ClickUpAttachments { return jsonDecode(result); } catch (e) { print(e); - return {"error": e.toString()}; + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); } } } diff --git a/lib/src/core/endpoints/auth.dart b/lib/src/core/endpoints/auth.dart new file mode 100644 index 0000000..32340d9 --- /dev/null +++ b/lib/src/core/endpoints/auth.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:http/http.dart'; + +class ClickUpAuth { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpAuth({required this.endPoint, required this.authToken, required this.httpClient}); + + /// Get access token based on your credentials. + // Future getAccessToken( + // {required String clientID, + // required String clientSecret, + // required String code}) async { + // try { + // final response = await post(Uri.parse( + // "$endPoint/oauth/token?client_id=$clientID&client_secret=$clientSecret&code=$code")); + // print(response.body); + // return response.body; + // } catch (e) { + // print(e.toString()); + // return e.toString(); + // } + // } + + /// Get the user bound to the token. + Future> getAuthorizedUser() async { + try { + final response = await httpClient.get(Uri.parse("$endPoint/user"), headers: { + "Authorization": authToken + }); + final user = jsonDecode(response.body); + return user; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Get the teams bound to authorized user. + Future> getAuthorizedTeams() async { + try { + final response = await httpClient.get(Uri.parse("$endPoint/team"), headers: { + "Authorization": authToken + }); + final teams = jsonDecode(response.body); + return teams; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/comments.dart b/lib/src/core/endpoints/comments.dart new file mode 100644 index 0000000..d76cea6 --- /dev/null +++ b/lib/src/core/endpoints/comments.dart @@ -0,0 +1,245 @@ +import 'dart:convert'; + +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:http/http.dart'; + +class ClickUpComments { + late String endPoint; + late String authToken; + late Client httpClient; + ClickUpComments( + {required this.endPoint, + required this.authToken, + required this.httpClient}); + + Future> getTaskComments({ + required String taskID, + bool useCustomTaskID = false, + int? teamID, + int? start, + String? startID, + }) async { + try { + final response = await httpClient.get( + Uri.parse(useCustomTaskID + ? "$endPoint/task/$taskID/comment?custom_task_ids=true&team_id=$teamID" + : "$endPoint/task/$taskID/comment"), + headers: {"Authorization": authToken}); + final comments = jsonDecode(response.body); + return comments; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Creates a comment on specific task in your space. Map model for the comment parameter is; + /// + /// ``` + /// { + /// "comment_text": "This is my sample comment", // Should be String. + /// "assignee": 123456, // Should be an int. + /// "notify_all": false // Should be a boolean. + /// } + /// ``` + + Future> createTaskComment({ + required String taskID, + required Map comment, + bool useCustomTaskID = false, + int? teamID, + }) async { + if (!comment.containsKey("comment_text") && + !comment.containsKey("assignee") && + !comment.containsKey("notify_all")) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your data does not match API's model requirements. Please check documentation."); + } + try { + final response = await httpClient.post( + Uri.parse(useCustomTaskID + ? "$endPoint/task/$taskID/comment?custom_task_ids=true&team_id=$teamID" + : "$endPoint/task/$taskID/comment"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(comment)); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getChatViewComments({ + required String viewID, + int? start, + String? startID, + }) async { + try { + final response = await httpClient.get( + Uri.parse(start != null && startID != null + ? "$endPoint/view/$viewID/comment?start=$start&start_id=$startID" + : "$endPoint/view/$viewID/comment"), + headers: { + "Authorization": authToken, + }); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> createChatViewComment({ + required String viewID, + required Map comment, + }) async { + if (!comment.containsKey("comment_text") && + !comment.containsKey("notify_all")) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your data does not match API's model requirements. Please check documentation."); + } + try { + final response = await httpClient.post( + Uri.parse("$endPoint/view/$viewID/comment"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(comment)); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getListComments({ + required double listID, + int? start, + String? startID, + }) async { + try { + final response = await httpClient.get( + Uri.parse(start != null && startID != null + ? "$endPoint/list/$listID/comment?start=$start&start_id=$startID" + : "$endPoint/list/$listID/comment"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> createListComment({ + required String listID, + required Map comment, + }) async { + if (!comment.containsKey("comment_text") && + !comment.containsKey("assignee") && + !comment.containsKey("notify_all")) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your data does not match API's model requirements. Please check documentation."); + } + + try { + final response = await httpClient.post( + Uri.parse("$endPoint/list/$listID/comment"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(comment)); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> updateComment({ + required double commentID, + required Map comment, + }) async { + if (!comment.containsKey("comment_text") && + !comment.containsKey("assignee") && + !comment.containsKey("resolved")) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your data does not match API's model requirements. Please check documentation."); + } + try { + final response = await httpClient.put( + Uri.parse("$endPoint/comment/$commentID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(comment)); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> deleteComment({ + required double commentID, + }) async { + try { + final response = await httpClient + .delete(Uri.parse("$endPoint/comment/$commentID"), headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final createdComment = jsonDecode(response.body); + return createdComment; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/custom_fields.dart b/lib/src/core/endpoints/custom_fields.dart new file mode 100644 index 0000000..1ebc89a --- /dev/null +++ b/lib/src/core/endpoints/custom_fields.dart @@ -0,0 +1,236 @@ +import 'dart:convert'; +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:http/http.dart'; + +enum CustomFieldType { url, number } + +class ClickUpCustomFields { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpCustomFields( + {required this.endPoint, + required this.authToken, + required this.httpClient}); + + Future> getAccessibleCustomFields( + {required String listID}) async { + try { + final response = await httpClient + .get(Uri.parse("$endPoint/list/$listID/field"), headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final customFields = jsonDecode(response.body); + return customFields; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Sets the Custom Field to functions value parameter. You'll need to know the "task_id" of the task you want to update, and the universal unique identifier (UUID) "field_id" of the Custom Field you want to set. Value must be one of the following depending of the field type; + /// + /// URL Custom Field: + /// ``` + /// { + /// "value": "This is sample URL", // Should be String. + /// } + /// ``` + /// + /// Dropdown Custom Field: + /// + /// Enter the universal unique identifier (UUID) of the dropdown menu option you want to set. You can find the UUIDs available for each getAccessibleCustomFields function. + /// ``` + /// { + /// "value": "03efda77-c7a0-42d3-8afd-fd546353c2f5", // Should be String. + /// } + /// ``` + /// + /// Email Custom Field: + /// ``` + /// { + /// "value": "example@example.com", // Should be String. + /// } + /// ``` + /// + /// Phone Custom Field: + /// ``` + /// { + /// "value": "+0 123 456 78 90", // Should be String. + /// } + /// ``` + /// + /// Date Custom Field: + /// + /// The value must be Unix time in milliseconds. To display the time in a Date Custom Field in ClickUp, you must include time: true in the value_options property. + /// ``` + /// { + /// "value":123456787, // Should be int. + /// "value_options": {"time": true} // Should be an Map. + /// } + /// ``` + /// + /// Short or Long Text Custom Field: + /// ``` + /// { + /// "value": "This is a sample text", // Should be String. + /// } + /// ``` + /// + /// Number Custom Field: + /// ``` + /// { + /// "value": 12345678, // Should be int. + /// } + /// ``` + /// + /// Money Custom Field: + /// + /// You can set an amount, but not the currency of a Money Custom Field via the SDK. You can check the currency of a Money Custom Field using getAccessibleCustomFields function. + /// ``` + /// { + /// "value": 12345678, // Should be int. + /// } + /// ``` + /// + /// Task Relationship Custom Field: + /// + /// Enter an array of task ids in the "add" property to add them to a Task Relationship Custom Field. Enter them into the "rem" property to remove tasks from the Relationship. + /// ``` + /// { + /// "value": { + /// "add": [ + /// "abcd1234", // Should be String. + /// "efghi5678" // Should be String. + /// ], + /// "rem": [ + /// "jklm9876", // Should be String. + /// "yuiop5678" // Should be String. + /// ] + /// } + /// } + /// ``` + /// People Custom Field: + /// + /// Enter an array of user ids in the add property to "add" them to a People Custom Field. Enter them into the "rem" property to remove users from a People Custom Field. You can get a list of people in the Workspace using getAuthorizedTeams function in workspaces. + /// ``` + /// { + /// "value": { + /// "add": [ + /// 123, // Should be int. + /// 456 // Should be int. + /// ], + /// "rem": [ + /// 987, // Should be int. + /// 765 // Should be int. + /// ] + /// } + /// } + /// ``` + /// Emoji (Rating) Custom Field: + /// + /// Enter an integer that is greater than or equal to zero and where the count property is greater than or equal to the value. You can find the count property for each Emoji (Rating) Custom Field using getAccessibleCustomFields function. + /// ``` + /// { + /// "value": 12345678, // Should be int. + /// } + /// ``` + /// Manual Progress Custom Field: + /// + /// Enter a number between the "start" and "end" values of each Manual Progress Custom Field. For example, for a field with "start": "10" and "end": "30", sending "current": "20" will be displayed as 50% complete in ClickUp. You can find the start and end values for each Manual Progress Custom Field using getAccessibleCustomFields function. + /// ``` + /// { + /// "value": { + /// "current": 50 // Should be int. + /// }, // Should be an Map. + /// } + /// ``` + /// + /// Label Custom Field: + /// + /// Enter an array of the universal unique identifiers (UUIDs) of the labels you want to apply. You can find the UUIDs available for each Label Custom Field using getAccessibleCustomFields function. + /// ``` + /// { + /// "value": ["03efda77-c7a0-42d3-8afd-fd546353c2f5", "30efda77-c7a0-42d3-8afd-fd546353c4a3"], // Should be array of Strings. + /// } + /// ``` + /// + /// Location Custom Field: + /// + /// Include the latitude, longitude, and formatted address as defined in the Google Maps Geocoding API. + /// ``` + /// { + /// "value":{ + /// "location": { + /// "lat": 1234, // Should be int. + /// "lng": 1234 // Should be int. + /// }, // Should be Map. + /// "formatted_address":"This is a sample address." // Should be String. + /// }, // Should be Map. + /// } + /// ``` + Future> setCustomFieldValue( + {required String taskID, + required String fieldID, + required Map value, + bool customTaskID = false, + double? teamID}) async { + if (!value.containsKey("value")) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your value model is invalid. Please read the function documentation."); + } + + try { + final response = await httpClient.post( + Uri.parse(customTaskID + ? "$endPoint/task/$taskID/field/$fieldID?custom_task_ids=true&team_id=$teamID" + : "$endPoint/task/$taskID/field/$fieldID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(value)); + final customFieldResponse = jsonDecode(response.body); + return customFieldResponse; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> removeCustomFieldValue( + {required String taskID, + required String fieldID, + bool customTaskID = false, + double? teamID}) async { + try { + final response = await httpClient.delete( + Uri.parse(customTaskID + ? "$endPoint/task/$taskID/field/$fieldID?custom_task_ids=true&team_id=$teamID" + : "$endPoint/task/$taskID/field/$fieldID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + ); + final customFieldResponse = jsonDecode(response.body); + return customFieldResponse; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/folders.dart b/lib/src/core/endpoints/folders.dart new file mode 100644 index 0000000..7dcd673 --- /dev/null +++ b/lib/src/core/endpoints/folders.dart @@ -0,0 +1,113 @@ +import 'dart:convert'; + +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:http/http.dart'; + +class ClickUpFolders { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpFolders( + {required this.endPoint, + required this.authToken, + required this.httpClient}); + + Future> getFolders( + {required double spaceID, bool includeArchived = false}) async { + try { + final response = await httpClient.get( + Uri.parse(includeArchived + ? "$endPoint/space/$spaceID/folder?archived=true" + : "$endPoint/space/$spaceID/folder"), + headers: { + "Authorization": authToken, + }); + final folders = jsonDecode(response.body); + return folders; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> createFolder( + {required double spaceID, required String name}) async { + try { + final response = await httpClient.post( + Uri.parse("$endPoint/space/$spaceID/folder"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({"name": name})); + final folder = jsonDecode(response.body); + return folder; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getFolder({required double folderID}) async { + try { + final response = await httpClient + .get(Uri.parse("$endPoint/folder/$folderID"), headers: { + "Authorization": authToken, + }); + final folder = jsonDecode(response.body); + return folder; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> updateFolder( + {required double folderID, required String name}) async { + try { + final response = await httpClient.put( + Uri.parse("$endPoint/folder/$folderID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({"name": name})); + final folders = jsonDecode(response.body); + return folders; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> deleteFolder({required double folderID}) async { + try { + final response = await httpClient + .delete(Uri.parse("$endPoint/folder/$folderID"), headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final folders = jsonDecode(response.body); + return folders; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/goals.dart b/lib/src/core/endpoints/goals.dart new file mode 100644 index 0000000..d392e23 --- /dev/null +++ b/lib/src/core/endpoints/goals.dart @@ -0,0 +1,226 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; + +import '../clickup_exception.dart'; + +class ClickUpGoals { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpGoals({required this.endPoint, required this.authToken, required this.httpClient}); + + /// View the Goals available in a Workspace. + + Future> getGoals({required double teamID, bool includeCompleted = false}) async { + try { + final response = await httpClient.get(Uri.parse(includeCompleted ? "$endPoint/team/$teamID/goal?include_completed=true" : "$endPoint/team/$teamID/goal"), headers: { + "Authorization": authToken, + }); + final goals = jsonDecode(response.body); + return goals; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Add a new Goal to a Workspace. + + Future> createGoal({required double teamID, required String goalName, required int dueDate, required String description, required bool multipleOwners, required List owners, required String color}) async { + try { + final response = await httpClient.post(Uri.parse("$endPoint/team/$teamID/goal"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": goalName, + "due_date": dueDate, + "description": description, + "multiple_owners": multipleOwners, + "owners": owners, + "color": color + })); + final goal = jsonDecode(response.body); + return goal; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// View the details of a Goal including its Targets. + /// + /// Goal ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + + Future> getGoal({required double goalID}) async { + try { + final response = await httpClient.get(Uri.parse("$endPoint/goal/$goalID"), headers: { + "Authorization": authToken, + }); + final goal = jsonDecode(response.body); + return goal; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Rename a Goal, set the due date, replace the description, add or remove owners, and set the Goal color. + /// + /// Goal ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + Future> updateGoal({required double goalID, required String goalName, required int dueDate, required String description, required List ownersToRemove, required List ownersToAdd, required String color}) async { + try { + final response = await httpClient.put(Uri.parse("$endPoint/goal/$goalID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": goalName, + "due_date": dueDate, + "description": description, + "rem_owners": ownersToRemove, + "add_owners": ownersToAdd, + "color": color + })); + final goal = jsonDecode(response.body); + return goal; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Remove a Goal from your Workspace. + /// + /// Goal ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + Future> deleteGoal({required double goalID}) async { + try { + final response = await httpClient.delete( + Uri.parse("$endPoint/goal/$goalID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + ); + final goal = jsonDecode(response.body); + return goal; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Add a Target to a Goal. + /// + /// Goal ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + /// + /// Type should be one of the ``["number","currency","boolean","percentage","automatic"]`` + + Future> createKeyResult({required double goalID, required String goalName, required List owners, required String type, required int stepsStart, required int stepsEnd, required String unit, required List taskIDs, required List listIDs}) async { + final allowedTypes = [ + "number", + "currency", + "boolean", + "percentage", + "automatic" + ]; + + if (!allowedTypes.contains(type)) { + throw ClickUpException(exceptionType: ClickUpExceptionType.invalidModel, exceptionMessage: "Please use one of the available types. Check function documentation for more information"); + } + + try { + final response = await httpClient.post(Uri.parse("$endPoint/goal/$goalID/key_result"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": goalName, + "owners": owners, + "type": type, + "steps_start": stepsStart, + "steps_end": stepsEnd, + "unit": unit, + "task_ids": taskIDs, + "list_ids": listIDs + })); + final keyResult = jsonDecode(response.body); + return keyResult; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Update a Target. + /// + /// Goal ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + /// + /// Type should be one of the ``["number","currency","boolean","percentage","automatic"]`` + + Future> editKeyResult({required double keyResultID, required String goalName, required List owners, required String type, required int stepsStart, required int stepsCurrent, required int stepsEnd, required String unit, required String note, required List taskIDs, required List listIDs}) async { + final allowedTypes = [ + "number", + "currency", + "boolean", + "percentage", + "automatic" + ]; + + if (!allowedTypes.contains(type)) { + throw ClickUpException(exceptionType: ClickUpExceptionType.invalidModel, exceptionMessage: "Please use one of the available types. Check function documentation for more information"); + } + + try { + final response = await httpClient.put(Uri.parse("$endPoint/key_result/$keyResultID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": goalName, + "owners": owners, + "type": type, + "steps_start": stepsStart, + "steps_end": stepsEnd, + "unit": unit, + "task_ids": taskIDs, + "list_ids": listIDs, + "steps_current": stepsCurrent, + "note": note + })); + final keyResult = jsonDecode(response.body); + return keyResult; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Update a Target. + /// + /// Goal ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + /// + /// Type should be one of the ``["number","currency","boolean","percentage","automatic"]`` + + Future> deleteKeyResult({required double keyResultID}) async { + try { + final response = await httpClient.delete( + Uri.parse("$endPoint/key_result/$keyResultID"), + headers: { + "Authorization": authToken, + }, + ); + final keyResult = jsonDecode(response.body); + return keyResult; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/guests.dart b/lib/src/core/endpoints/guests.dart new file mode 100644 index 0000000..29d8595 --- /dev/null +++ b/lib/src/core/endpoints/guests.dart @@ -0,0 +1,256 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; + +import '../clickup_exception.dart'; + +class ClickUpGuests { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpGuests({required this.endPoint, required this.authToken, required this.httpClient}); + + /// Invite a guest to join a Workspace. To invite a member to your Workspace, use the Invite User to Workspace endpoint. + /// + /// You'll also need to grant the guest access to specific items using the following endpoints: Add Guest to Folder, Add Guest to List, or Add Guest to Task. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> inviteGuestToWorkspace({required double teamID, required String email, required bool canEditTags, required bool canSeeTimeSpent, required bool canSeeTimeEstimated, required bool canCreateViews, required int customRoleID}) async { + try { + final response = await httpClient.post(Uri.parse("$endPoint/team/$teamID/guest"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "email": email, + "can_edit_tags": canEditTags, + "can_see_time_spent": canSeeTimeSpent, + "can_see_time_estimated": canSeeTimeEstimated, + "can_create_views": canCreateViews, + "custom_role_id": customRoleID + })); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// View information about a guest. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> getGuest({required double teamID, required double guestID}) async { + try { + final response = await httpClient.get(Uri.parse("$endPoint/team/$teamID/guest/$guestID"), headers: { + "Authorization": authToken, + }); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Rename and configure options for a guest. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> editGuestOnWorkspace({required double teamID, required double guestID, required String username, required bool canEditTags, required bool canSeeTimeSpent, required bool canSeeTimeEstimated, required bool canCreateViews, required int customRoleID}) async { + try { + final response = await httpClient.put(Uri.parse("$endPoint/team/$teamID/guest/$guestID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "username": username, + "can_edit_tags": canEditTags, + "can_see_time_spent": canSeeTimeSpent, + "can_see_time_estimated": canSeeTimeEstimated, + "can_create_views": canCreateViews, + "custom_role_id": customRoleID + })); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Revoke a guest's access to a Workspace. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> removeGuestFromWorkspace({required double teamID, required double guestID}) async { + try { + final response = await httpClient.delete(Uri.parse("$endPoint/team/$teamID/guest/$guestID"), headers: { + "Authorization": authToken, + }); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Share a task with a guest. + /// + /// Allowed permissions are ``["read", "comment", "edit", "create"]`` + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> addGuestToTask({required String taskID, required double guestID, required String permissionLevel, bool includeShared = true, bool useCustomTaskID = false, double teamID = 0}) async { + final allowedPermissions = [ + "read", + "comment", + "edit", + "create" + ]; + + if (!allowedPermissions.contains(permissionLevel)) { + throw ClickUpException(exceptionType: ClickUpExceptionType.invalidModel, exceptionMessage: "You need to select one of the allowed permissions for the guest user."); + } + try { + final response = await httpClient.post(Uri.parse(useCustomTaskID ? "$endPoint/task/$taskID/guest/$guestID?include_shared=$includeShared&custom_task_ids=true&team_id=$teamID" : "$endPoint/task/$taskID/guest/$guestID?include_shared=$includeShared"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "permission_level": permissionLevel + })); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Revoke a guest's access to a task. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> removeGuestFromTask({required String taskID, required double guestID, bool includeShared = true, bool useCustomTaskID = false, double teamID = 0}) async { + try { + final response = await httpClient.delete(Uri.parse(useCustomTaskID ? "$endPoint/task/$taskID/guest/$guestID?include_shared=$includeShared&custom_task_ids=true&team_id=$teamID" : "$endPoint/task/$taskID/guest/$guestID?include_shared=$includeShared"), headers: { + "Authorization": authToken + }); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Share a List with a guest. + /// + /// Allowed permissions are ``["read", "comment", "edit", "create"]`` + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> addGuestToList({required double listID, required double guestID, required String permissionLevel, bool includeShared = true}) async { + final allowedPermissions = [ + "read", + "comment", + "edit", + "create" + ]; + + if (!allowedPermissions.contains(permissionLevel)) { + throw ClickUpException(exceptionType: ClickUpExceptionType.invalidModel, exceptionMessage: "You need to select one of the allowed permissions for the guest user."); + } + try { + final response = await httpClient.post(Uri.parse("$endPoint/list/$listID/guest/$guestID?include_shared=$includeShared"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "permission_level": permissionLevel + })); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Revoke a guest's access to a List. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> removeGuestFromList({required double listID, required double guestID, bool includeShared = true}) async { + try { + final response = await httpClient.delete(Uri.parse("$endPoint/list/$listID/guest/$guestID?include_shared=$includeShared"), headers: { + "Authorization": authToken + }); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Share a Folder with a guest. + /// + /// Allowed permissions are ``["read", "comment", "edit", "create"]`` + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> addGuestToFolder({required double folderID, required double guestID, required String permissionLevel, bool includeShared = true}) async { + final allowedPermissions = [ + "read", + "comment", + "edit", + "create" + ]; + + if (!allowedPermissions.contains(permissionLevel)) { + throw ClickUpException(exceptionType: ClickUpExceptionType.invalidModel, exceptionMessage: "You need to select one of the allowed permissions for the guest user."); + } + try { + final response = await httpClient.post(Uri.parse("$endPoint/folder/$folderID/guest/$guestID?include_shared=$includeShared"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "permission_level": permissionLevel + })); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Revoke a guest's access to a Folder. + /// + /// Note: This endpoint is only available to Workspaces on our Enterprise Plan. + + Future> removeGuestFromFolder({required double folderID, required double guestID, bool includeShared = true}) async { + try { + final response = await httpClient.delete(Uri.parse("$endPoint/folder/$folderID/guest/$guestID?include_shared=$includeShared"), headers: { + "Authorization": authToken + }); + final guest = jsonDecode(response.body); + return guest; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/lists.dart b/lib/src/core/endpoints/lists.dart new file mode 100644 index 0000000..7ab0ed9 --- /dev/null +++ b/lib/src/core/endpoints/lists.dart @@ -0,0 +1,85 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; + +import '../clickup_exception.dart'; + +class ClickUpLists { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpLists({required this.endPoint, required this.authToken, required this.httpClient}); + + /// View the Lists within a Folder. + + Future> getLists({required double folderID, bool archived = false}) async { + try { + final response = await httpClient.get(Uri.parse("$endPoint/folder/$folderID/list?archived=$archived"), headers: { + "Authorization": authToken, + }); + final goals = jsonDecode(response.body); + return goals; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Add a new List to a Folder. + /// + /// Include a ``assignee`` to assign this List. + /// + /// Status refers to the List color rather than the task Statuses available in the List. + + Future> createList({required double folderID, required String listName, String? content, int? dueDate, bool? dueDateTime, int? priority, int? assignee, String? status}) async { + Map body = { + "name": listName + }; + + content != null + ? body.addAll({ + "content": content + }) + : () => {}; + dueDate != null + ? body.addAll({ + "due_date": dueDate + }) + : () => {}; + dueDateTime != null + ? body.addAll({ + "due_date_time": dueDateTime + }) + : () => {}; + priority != null + ? body.addAll({ + "priority": priority + }) + : () => {}; + assignee != null + ? body.addAll({ + "assignee": assignee + }) + : () => {}; + status != null + ? body.addAll({ + "status": status + }) + : () => {}; + + try { + final response = await httpClient.post(Uri.parse("$endPoint/folder/$folderID/list"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(body)); + final goals = jsonDecode(response.body); + return goals; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/members.dart b/lib/src/core/endpoints/members.dart new file mode 100644 index 0000000..1a52e42 --- /dev/null +++ b/lib/src/core/endpoints/members.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpMembers { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpMembers( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/roles.dart b/lib/src/core/endpoints/roles.dart new file mode 100644 index 0000000..26067f2 --- /dev/null +++ b/lib/src/core/endpoints/roles.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpRoles { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpRoles( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/shared_hierarchy.dart b/lib/src/core/endpoints/shared_hierarchy.dart new file mode 100644 index 0000000..6d18711 --- /dev/null +++ b/lib/src/core/endpoints/shared_hierarchy.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpSharedHierarchy { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpSharedHierarchy( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/spaces.dart b/lib/src/core/endpoints/spaces.dart new file mode 100644 index 0000000..560dff7 --- /dev/null +++ b/lib/src/core/endpoints/spaces.dart @@ -0,0 +1,168 @@ +import 'dart:convert'; + +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:http/http.dart'; + +class ClickUpSpaces { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpSpaces( + {required this.endPoint, + required this.authToken, + required this.httpClient}); + + final Map sampleSpaceSchema = { + "name": "Test Space", + "multiple_assignees": false, + "features": { + "due_dates": { + "enabled": false, + "start_date": false, + "remap_due_dates": false, + "remap_closed_due_date": false + }, + "time_tracking": {"enabled": false}, + "tags": {"enabled": false}, + "time_estimates": {"enabled": false}, + "checklists": {"enabled": false}, + "custom_fields": {"enabled": false}, + "remap_dependencies": {"enabled": false}, + "dependency_warning": {"enabled": false}, + "portfolios": {"enabled": false}, + } + }; + + Future> getSpaces( + {required double teamID, bool includeArchived = false}) async { + try { + final response = await httpClient.get( + Uri.parse(includeArchived + ? "$endPoint/team/$teamID/space?archived=true" + : "$endPoint/team/$teamID/space"), + headers: { + "Authorization": authToken, + }); + final spaces = jsonDecode(response.body); + return spaces; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> createSpace( + {required double teamID, + required Map spaceSchema}) async { + bool schemaMatch = false; + for (var key in spaceSchema.keys) { + schemaMatch = sampleSpaceSchema.containsKey(key); + if (!schemaMatch) { + break; + } + } + + if (!schemaMatch) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your value model is invalid. Please read the function documentation."); + } + + try { + final response = await httpClient.post( + Uri.parse("$endPoint/team/$teamID/space"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(spaceSchema)); + final space = jsonDecode(response.body); + return space; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getSpace({required double spaceID}) async { + try { + final response = + await httpClient.get(Uri.parse("$endPoint/space/$spaceID"), headers: { + "Authorization": authToken, + }); + final space = jsonDecode(response.body); + return space; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> updateSpace( + {required double spaceID, + required Map spaceSchema}) async { + bool schemaMatch = false; + schemaMatch = spaceSchema.containsKey("color"); + schemaMatch = spaceSchema.containsKey("private"); + schemaMatch = spaceSchema.containsKey("admin_can_manage"); + for (var key in spaceSchema.keys) { + if (key != "color" && key != "private" && key != "admin_can_manage") { + schemaMatch = sampleSpaceSchema.containsKey(key); + } + if (!schemaMatch) { + break; + } + } + if (!schemaMatch) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: + "Your value model is invalid. Please read the function documentation."); + } + try { + final response = await httpClient.put( + Uri.parse("$endPoint/space/$spaceID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(spaceSchema)); + final folders = jsonDecode(response.body); + return folders; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> deleteSpace({required double spaceID}) async { + try { + final response = await httpClient + .delete(Uri.parse("$endPoint/folder/$spaceID"), headers: { + "Authorization": authToken, + }); + final folders = jsonDecode(response.body); + return folders; + } catch (e) { + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/tags.dart b/lib/src/core/endpoints/tags.dart new file mode 100644 index 0000000..1df1666 --- /dev/null +++ b/lib/src/core/endpoints/tags.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpTags { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTags( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/task_checklists.dart b/lib/src/core/endpoints/task_checklists.dart new file mode 100644 index 0000000..1c68893 --- /dev/null +++ b/lib/src/core/endpoints/task_checklists.dart @@ -0,0 +1,141 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; + +import '../clickup_exception.dart'; + +class ClickUpTaskChecklists { + late String endPoint; + late String authToken; + late Client httpClient; + ClickUpTaskChecklists({required this.endPoint, required this.authToken, required this.httpClient}); + + /// Adds a new checklist on a specific task in your space. + + Future> createChecklist({required String checklistName, required String taskID, bool useCustomTaskID = false, double teamID = 0}) async { + try { + final response = await httpClient.post(Uri.parse(useCustomTaskID ? "$endPoint/task/$taskID/checklist?custom_task_ids=true&team_id=$teamID" : "$endPoint/task/$taskID/checklist"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": checklistName + })); + final checklist = jsonDecode(response.body); + return checklist; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Rename a task checklist, or reorder a checklist so it appears above or below other checklists on a task. + /// + /// Checklist ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + /// + /// Position refers to the order of appearance of checklists on a task. To set a checklist to appear at the top of the checklists section of a task, use ``"position": 0``. + + Future> editChecklist({required String checklistName, required int position, required String checklistID}) async { + try { + final response = await httpClient.put(Uri.parse("$endPoint/checklist/$checklistID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": checklistName, + "position": position + })); + final checklist = jsonDecode(response.body); + return checklist; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Delete a checklist from a task. + /// + /// Checklist ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + + Future> deleteChecklist({required String checklistID}) async { + try { + final response = await httpClient.delete(Uri.parse("$endPoint/checklist/$checklistID"), headers: { + "Authorization": authToken, + }); + final checklist = jsonDecode(response.body); + return checklist; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Add a line item to a task checklist. + /// + /// Checklist ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + + Future> createChecklistItem({required String checklistName, required int assignee, required String checklistID}) async { + try { + final response = await httpClient.post(Uri.parse("$endPoint/checklist/$checklistID/checklist_item"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": checklistName, + "assignee": assignee + })); + final checklist = jsonDecode(response.body); + return checklist; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Update an individual line item in a task checklist. You can rename it, set the assignee, mark it as resolved, or nest it under another checklist item. + /// + /// Checklist ID and Checklist Item ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + /// + /// To nest a checklist item under another checklist item, include the other item's ``checklistItemId``. + + Future> editChecklistItem({required String checklistName, String assignee = "null", required bool resolved, String parent = "null", required String checklistID, required String checklistItemID}) async { + try { + final response = await httpClient.put(Uri.parse("$endPoint/checklist/$checklistID/checklist_item/$checklistItemID"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode({ + "name": checklistName, + "assignee": assignee, + "resolved": resolved, + "parent": parent + })); + final checklist = jsonDecode(response.body); + return checklist; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Delete a line item from a task checklist. + /// + /// Checklist ID and Checklist Item ID should be a valid UUID ``(b8a8-48d8-a0c6-b4200788a683)`` + + Future> deleteChecklistItem({required String checklistID, required String checklistItemID}) async { + try { + final response = await httpClient.delete(Uri.parse("$endPoint/checklist/$checklistID/checklist_item/$checklistItemID"), headers: { + "Authorization": authToken, + }); + final checklist = jsonDecode(response.body); + return checklist; + } catch (e) { + print(e.toString()); + throw ClickUpException(exceptionType: ClickUpExceptionType.requestError, exceptionMessage: "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/task_relationships.dart b/lib/src/core/endpoints/task_relationships.dart new file mode 100644 index 0000000..018bf5f --- /dev/null +++ b/lib/src/core/endpoints/task_relationships.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpTaskRelationships { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTaskRelationships( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/task_templates.dart b/lib/src/core/endpoints/task_templates.dart new file mode 100644 index 0000000..1507496 --- /dev/null +++ b/lib/src/core/endpoints/task_templates.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpTaskTemplates { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTaskTemplates( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/tasks.dart b/lib/src/core/endpoints/tasks.dart new file mode 100644 index 0000000..2a6d158 --- /dev/null +++ b/lib/src/core/endpoints/tasks.dart @@ -0,0 +1,400 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; + +import '../clickup_exception.dart'; + +class ClickUpTasks { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTasks( + {required this.endPoint, + required this.authToken, + required this.httpClient}); + + Future> getTasks({ + required double listID, + bool archived = false, + int page = 0, + String orderBy = "created", + bool reverse = true, + bool subtasks = true, + String statuses = "", + bool includeClosed = false, + List assignees = const [], + List tags = const [], + int dueDateGreaterThan = 0, + int dueDateLessThan = 0, + int dateCreatedGreaterThan = 0, + int dateCreatedLessThan = 0, + int dateUpdatedGreaterThan = 0, + int dateUpdatedLessThan = 0, + int dateDoneGreaterThan = 0, + int dateDoneLessThan = 0, + List> customFields = const [], + }) async { + ////TO:DO Parameter validation + + var assigneeQuery = ""; + var tagQuery = ""; + var customFieldQuery = "custom_fields=[${customFields.toString()}]"; + if (assignees.isNotEmpty) { + for (var assignee in assignees) { + assigneeQuery = "assignees[]=$assignee&"; + print(assigneeQuery.length); + assigneeQuery = assigneeQuery.substring(0, assigneeQuery.length - 1); + } + } + if (tags.isNotEmpty) { + for (var tag in tags) { + tagQuery = "tags[]=$tag&"; + } + tagQuery = assigneeQuery.substring(0, assigneeQuery.length - 1); + } + + final queryParams = + "?archived=$archived&page=$page&order_by=$orderBy&reverse=$reverse&subtasks=$subtasks&statuses=$statuses&include_closed=$includeClosed&assignees=$assigneeQuery&tags=$tagQuery&due_date_gt=$dueDateGreaterThan&due_date_lt=$dueDateLessThan&date_created_gt=$dateCreatedGreaterThan&date_created_lt=$dateCreatedLessThan&date_updated_gt=$dateUpdatedGreaterThan&date_updated_lt=$dateUpdatedLessThan&date_done_gt=$dateDoneGreaterThan&date_done_lt=$dateDoneGreaterThan&custom_fields=$customFieldQuery"; + try { + final response = await httpClient.get( + Uri.parse("$endPoint/list/$listID/task$queryParams"), + headers: {"Authorization": authToken}); + final List tasks = jsonDecode(response.body); + return tasks.first; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Sample Task Schema + /// ``` + /// { + /// "name": "", + /// "description": "", + /// "assignees": [], //List of integers + /// "tags": [], //List of Strings + /// "status": "", + /// "priority": 0, + /// "due_date": 0, + /// "due_date_time": false, + /// "time_estimate": 0, + /// "start_date": 0, + /// "start_date_time": false, + /// "notify_all": false, + /// "parent": "", + /// "links_to": "", + /// "check_required_custom_fields": false, + /// "custom_fields": [] // List of Maps + /// } + /// ``` + + Future> createTask({ + required double listID, + required Map taskDescription, + bool customTaskIDs = false, + double teamID = 0, + }) async { + ////TO:DO Parameter validation + + var queryParams = ""; + if (customTaskIDs) { + queryParams = "?${queryParams}custom_task_ids=true"; + if (teamID != 0) { + queryParams = "$queryParams&team_id=$teamID"; + } + } + + try { + final response = await httpClient.post( + Uri.parse("$endPoint/list/$listID/task$queryParams"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(taskDescription)); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getTask( + {required double taskID, + bool customTaskIDs = false, + double teamID = 0, + bool includeSubtasks = false}) async { + ////TO:DO Parameter validation + + var queryParams = ""; + if (customTaskIDs && teamID != 0) { + queryParams = "?${queryParams}custom_task_ids=true&team_id=$teamID"; + if (includeSubtasks) { + queryParams = "$queryParams&include_subtasks=true"; + } + } else if (includeSubtasks) { + queryParams = "?include_subtasks=true"; + } + + try { + final response = await httpClient + .get(Uri.parse("$endPoint/task/$taskID$queryParams"), headers: { + "Authorization": authToken, + }); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Sample Task Schema + /// ``` + /// { + /// "name": "", + /// "description": "", + /// "status": "", + /// "priority": 0, + /// "due_date": 0, + /// "due_date_time": false, + /// "parent": "", + /// "time_estimate": 0, + /// "start_date": 0, + /// "start_date_time": false, + /// "assignees": { + /// "add": [], + /// "rem": [] + /// }, //List of integers + /// "archived": false + /// } + /// ``` + Future> updateTask({ + required double taskID, + required Map taskDescription, + bool customTaskIDs = false, + double teamID = 0, + }) async { + ////TO:DO Parameter validation + + var queryParams = ""; + if (customTaskIDs) { + queryParams = "?${queryParams}custom_task_ids=true"; + if (teamID != 0) { + queryParams = "$queryParams&team_id=$teamID"; + } + } + + try { + final response = await httpClient.put( + Uri.parse("$endPoint/task/$taskID$queryParams"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }, + body: jsonEncode(taskDescription)); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> deleteTask({ + required double taskID, + bool customTaskIDs = false, + double teamID = 0, + }) async { + ////TO:DO Parameter validation + + var queryParams = ""; + if (customTaskIDs) { + queryParams = "?${queryParams}custom_task_ids=true"; + if (teamID != 0) { + queryParams = "$queryParams&team_id=$teamID"; + } + } + + try { + final response = await httpClient + .delete(Uri.parse("$endPoint/task/$taskID$queryParams"), headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + /// Order by Options include: id, created, updated, and due_date. + Future> getFilteredTeamTasks({ + required double workspaceTeamID, + int page = 0, + String orderBy = "created", + bool reverse = false, + bool subtasks = false, + List spaceIDs = const [], + List projectIDs = const [], + List listIDs = const [], + List statuses = const [], + bool includeClosed = false, + List assignees = const [], + List tags = const [], + int dueDateGreaterThan = 0, + int dueDateLessThan = 0, + int dateCreatedGreaterThan = 0, + int dateCreatedLessThan = 0, + int dateUpdatedGreaterThan = 0, + int dateUpdatedLessThan = 0, + int dateDoneGreaterThan = 0, + int dateDoneLessThan = 0, + List> customFields = const [], + bool customTaskIDs = false, + double teamID = 0, + String parent = "", + }) async { + ////TO:DO Parameter validation + var spaceIDsQuery = ""; + var projectIDsQuery = ""; + var listIDsQuery = ""; + var statusesQuery = ""; + var assigneesQuery = ""; + var tagsQuery = ""; + var customFieldsQuery = ""; + + var queryParams = + "?page=$page&order_by=$orderBy&reverse=$reverse&subtasks=$subtasks&space_ids=$spaceIDsQuery&project_ids=$projectIDsQuery&list_ids=$listIDsQuery&statuses=$statusesQuery&include_closed=$includeClosed&assignees=$assigneesQuery&tags=$tagsQuery&due_date_gt=$dueDateGreaterThan&due_date_lt=$dueDateLessThan&date_created_gt=$dateCreatedGreaterThan&date_created_lt=$dateCreatedLessThan&date_updated_gt=$dateUpdatedGreaterThan&date_updated_lt=$dateUpdatedLessThan&date_done_gt=$dateDoneGreaterThan&date_done_lt=$dateDoneLessThan&custom_fields=$customFieldsQuery"; + if (customTaskIDs) { + queryParams = "${queryParams}custom_task_ids=true"; + if (teamID != 0) { + queryParams = "$queryParams&team_id=$teamID"; + } + } + if (parent.isNotEmpty) { + queryParams = "$queryParams&parent=string"; + } + + try { + final response = await httpClient.get( + Uri.parse("$endPoint/team/$workspaceTeamID/task$queryParams"), + headers: { + "Authorization": authToken, + }); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getTasksTimeInStatus({ + required String taskID, + bool customTaskIDs = false, + double teamID = 0, + }) async { + ////TO:DO Parameter validation + + var queryParams = ""; + if (customTaskIDs) { + queryParams = "?${queryParams}custom_task_ids=true"; + if (teamID != 0) { + queryParams = "$queryParams&team_id=$teamID"; + } + } + + try { + final response = await httpClient.get( + Uri.parse("$endPoint/task/$taskID/time_in_status$queryParams"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } + + Future> getBulkTasksTimeInStatus({ + required List taskIDs, + bool customTaskIDs = false, + double teamID = 0, + }) async { + if (taskIDs.length > 99) { + throw ClickUpException( + exceptionType: ClickUpExceptionType.invalidModel, + exceptionMessage: "You can only query up to 100 tasks per request"); + } + ////TO:DO Parameter validation + var queryParams = "?"; + final template = "task_ids="; + for (var taskID in taskIDs) { + queryParams = "$queryParams$template$taskID&"; + } + if (customTaskIDs) { + queryParams = "${queryParams}custom_task_ids=true"; + if (teamID != 0) { + queryParams = "$queryParams&team_id=$teamID"; + } + } + if (queryParams.isNotEmpty) { + queryParams = queryParams.substring(0, queryParams.length - 1); + } + + try { + final response = await httpClient.get( + Uri.parse("$endPoint/task/bulk_time_in_status/task_ids$queryParams"), + headers: { + "Authorization": authToken, + "Content-Type": "application/json" + }); + final task = jsonDecode(response.body); + return task; + } catch (e) { + print(e); + print(e.toString()); + throw ClickUpException( + exceptionType: ClickUpExceptionType.requestError, + exceptionMessage: + "An error occured while making the request. Error is ${e.toString()}"); + } + } +} diff --git a/lib/src/core/endpoints/teams.dart b/lib/src/core/endpoints/teams.dart new file mode 100644 index 0000000..ccde3b6 --- /dev/null +++ b/lib/src/core/endpoints/teams.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpTeams { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTeams( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/time_tracking_legacy.dart b/lib/src/core/endpoints/time_tracking_legacy.dart new file mode 100644 index 0000000..6fc3b78 --- /dev/null +++ b/lib/src/core/endpoints/time_tracking_legacy.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpTimeTrackingLegacy { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTimeTrackingLegacy( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/time_tracking_v2.dart b/lib/src/core/endpoints/time_tracking_v2.dart new file mode 100644 index 0000000..c850703 --- /dev/null +++ b/lib/src/core/endpoints/time_tracking_v2.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpTimeTrackingV2 { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpTimeTrackingV2( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/users.dart b/lib/src/core/endpoints/users.dart new file mode 100644 index 0000000..cbd505c --- /dev/null +++ b/lib/src/core/endpoints/users.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpUsers { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpUsers( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/views.dart b/lib/src/core/endpoints/views.dart new file mode 100644 index 0000000..76064bb --- /dev/null +++ b/lib/src/core/endpoints/views.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpViews { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpViews( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/core/endpoints/webhooks.dart b/lib/src/core/endpoints/webhooks.dart new file mode 100644 index 0000000..f4bf2fa --- /dev/null +++ b/lib/src/core/endpoints/webhooks.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +class ClickUpWebhooks { + late String endPoint; + late String authToken; + late Client httpClient; + + ClickUpWebhooks( + {required this.endPoint, + required this.authToken, + required this.httpClient}); +} diff --git a/lib/src/custom_fields/custom_fields.dart b/lib/src/custom_fields/custom_fields.dart deleted file mode 100644 index 6788af1..0000000 --- a/lib/src/custom_fields/custom_fields.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpCustomFields { - late String endPoint; - late String authToken; - - ClickUpCustomFields({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/dependencies/dependencies.dart b/lib/src/dependencies/dependencies.dart deleted file mode 100644 index accde90..0000000 --- a/lib/src/dependencies/dependencies.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpDependencies { - late String endPoint; - late String authToken; - - ClickUpDependencies({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/folders/folders.dart b/lib/src/folders/folders.dart deleted file mode 100644 index eb24c22..0000000 --- a/lib/src/folders/folders.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpFolders { - late String endPoint; - late String authToken; - - ClickUpFolders({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/goals/goals.dart b/lib/src/goals/goals.dart deleted file mode 100644 index 25bb66b..0000000 --- a/lib/src/goals/goals.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpGoals { - late String endPoint; - late String authToken; - - ClickUpGoals({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/guests/guests.dart b/lib/src/guests/guests.dart deleted file mode 100644 index d6e9b65..0000000 --- a/lib/src/guests/guests.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpGuests { - late String endPoint; - late String authToken; - - ClickUpGuests({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/lists/lists.dart b/lib/src/lists/lists.dart deleted file mode 100644 index 36df4d9..0000000 --- a/lib/src/lists/lists.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpLists { - late String endPoint; - late String authToken; - - ClickUpLists({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/members/members.dart b/lib/src/members/members.dart deleted file mode 100644 index b754ddc..0000000 --- a/lib/src/members/members.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpMembers { - late String endPoint; - late String authToken; - - ClickUpMembers({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/roles/roles.dart b/lib/src/roles/roles.dart deleted file mode 100644 index 5c708d7..0000000 --- a/lib/src/roles/roles.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpRoles { - late String endPoint; - late String authToken; - - ClickUpRoles({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/shared_hierarchy/shared_hierarchy.dart b/lib/src/shared_hierarchy/shared_hierarchy.dart deleted file mode 100644 index 4fcfa47..0000000 --- a/lib/src/shared_hierarchy/shared_hierarchy.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpSharedHierarchy { - late String endPoint; - late String authToken; - - ClickUpSharedHierarchy({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/spaces/spaces.dart b/lib/src/spaces/spaces.dart deleted file mode 100644 index eedf322..0000000 --- a/lib/src/spaces/spaces.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpSpaces { - late String endPoint; - late String authToken; - - ClickUpSpaces({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/tags/tags.dart b/lib/src/tags/tags.dart deleted file mode 100644 index 10fc3aa..0000000 --- a/lib/src/tags/tags.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpTags { - late String endPoint; - late String authToken; - - ClickUpTags({required this.endPoint, required this.authToken}); -} diff --git a/lib/src/tasks/task_templates.dart b/lib/src/tasks/task_templates.dart deleted file mode 100644 index 2b8c944..0000000 --- a/lib/src/tasks/task_templates.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpTaskTemplates{ - late String endPoint; - late String authToken; - - ClickUpTaskTemplates({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/tasks/tasks.dart b/lib/src/tasks/tasks.dart deleted file mode 100644 index cdd349b..0000000 --- a/lib/src/tasks/tasks.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpTasks{ - late String endPoint; - late String authToken; - - ClickUpTasks({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/teams/teams.dart b/lib/src/teams/teams.dart deleted file mode 100644 index 145b6fa..0000000 --- a/lib/src/teams/teams.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpTeams{ - late String endPoint; - late String authToken; - - ClickUpTeams({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/time_tracking/time_tracking_legacy.dart b/lib/src/time_tracking/time_tracking_legacy.dart deleted file mode 100644 index 1f70476..0000000 --- a/lib/src/time_tracking/time_tracking_legacy.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpTimeTrackingLegacy{ - late String endPoint; - late String authToken; - - ClickUpTimeTrackingLegacy({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/time_tracking/time_tracking_v2.dart b/lib/src/time_tracking/time_tracking_v2.dart deleted file mode 100644 index 00cafad..0000000 --- a/lib/src/time_tracking/time_tracking_v2.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpTimeTrackingV2{ - late String endPoint; - late String authToken; - - ClickUpTimeTrackingV2({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/users/users.dart b/lib/src/users/users.dart deleted file mode 100644 index a087a2e..0000000 --- a/lib/src/users/users.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpUsers{ - late String endPoint; - late String authToken; - - ClickUpUsers({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/views/views.dart b/lib/src/views/views.dart deleted file mode 100644 index 0cbb0c9..0000000 --- a/lib/src/views/views.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpViews{ - late String endPoint; - late String authToken; - - ClickUpViews({required this.endPoint, required this.authToken}); -} \ No newline at end of file diff --git a/lib/src/webhooks/webhooks.dart b/lib/src/webhooks/webhooks.dart deleted file mode 100644 index 062f247..0000000 --- a/lib/src/webhooks/webhooks.dart +++ /dev/null @@ -1,6 +0,0 @@ -class ClickUpWebhooks { - late String endPoint; - late String authToken; - - ClickUpWebhooks({required this.endPoint, required this.authToken}); -} diff --git a/pubspec.yaml b/pubspec.yaml index 2b90f7b..14eb33b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,13 +1,14 @@ -name: clickup_dart -description: An API wrapper for ClickUp for creating applications on top of the product. -version: 0.1.0 -repository: https://github.com/ayazemre/clickup-dart +name: clickup_dart_sdk +description: A SDK for ClickUp for integrating or creating applications on top of the product. +version: 0.4.0 +repository: https://github.com/ayazemre/clickup-dart-sdk environment: - sdk: '>=2.18.5 <3.0.0' + sdk: '>=2.18.5 <4.0.0' dev_dependencies: lints: ^2.0.0 test: ^1.16.0 dependencies: http: ^0.13.5 + path: ^1.8.3 diff --git a/test/e2e/clickup_dart_sdk_sample_user_behaviour_test.dart b/test/e2e/clickup_dart_sdk_sample_user_behaviour_test.dart new file mode 100644 index 0000000..3bc0b66 --- /dev/null +++ b/test/e2e/clickup_dart_sdk_sample_user_behaviour_test.dart @@ -0,0 +1,24 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('User Behaviour Samples', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + group("User Logs in, creates a task and uploads a file.", () { + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + expect(user.containsKey("user"), true); + }); + }); + }); +} diff --git a/test/integration/attachment_test.dart b/test/integration/attachment_test.dart new file mode 100644 index 0000000..7b83d46 --- /dev/null +++ b/test/integration/attachment_test.dart @@ -0,0 +1,32 @@ +import 'package:path/path.dart' as p; + +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + + group('Attachment Test', () { + setUp(() async { + // Setting up the SDK with a random token and mock server. ClickUp's official mock server accepts random tokens as valid tokens. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Upload an attachment', () async { + final response = await clickUp.attachments.createTaskAttachment( + filePath: + p.join(p.current, "test", "integration", "beksinski_sample.jpg"), + taskID: "213123", + useCustomTaskID: false); + expect(response, { + 'message': + 'Mock server error. Media type multipart/form-data deserialization is not supported.' + }); + }); + }); +} diff --git a/test/clickup_dart_sdk_test.dart b/test/integration/auth_test.dart similarity index 50% rename from test/clickup_dart_sdk_test.dart rename to test/integration/auth_test.dart index cc374d3..2be8e00 100644 --- a/test/clickup_dart_sdk_test.dart +++ b/test/integration/auth_test.dart @@ -1,12 +1,12 @@ -import 'package:clickup_dart/clickup_dart_sdk.dart'; +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; import 'package:test/test.dart'; void main() { late String token; late ClickUp clickUp; - group('API endpoint Tests', () { + group('Authorization Tests', () { setUp(() async { - // Additional setup goes here. + // Setting up the SDK with a random token and mock server. ClickUp's official mock server accepts random tokens as valid tokens. token = "pk_qwerty123456"; clickUp = ClickUp( apiEndpoint: @@ -14,25 +14,13 @@ void main() { ..initialize(authToken: token); }); - /// TO-DO: Oauth Testing - /// test('Authorization - Get Authorized User', () async { final user = await clickUp.auth.getAuthorizedUser(); - print(user); expect(user.containsKey("user"), true); }); - test('Authorization - Get Authorized Teams', () async { + test('Authorization - Get Authorized Teams(Workspaces)', () async { final teams = await clickUp.auth.getAuthorizedTeams(); - print(teams); expect(teams.containsKey("teams"), true); }); - test('Attachments - Create Task Attachment', () async { - final attachment = await clickUp.attachments.createTaskAttachment( - taskID: "8669e046h", - useCustomTaskID: false, - filePath: "./test/beksinski_sample.jpg"); - print(attachment); - expect(attachment.containsKey("message"), true); - }); }); } diff --git a/test/beksinski_sample.jpg b/test/integration/beksinski_sample.jpg similarity index 100% rename from test/beksinski_sample.jpg rename to test/integration/beksinski_sample.jpg diff --git a/test/integration/comments_test.dart b/test/integration/comments_test.dart new file mode 100644 index 0000000..ce59c93 --- /dev/null +++ b/test/integration/comments_test.dart @@ -0,0 +1,117 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('Comments Tests', () { + setUp(() async { + // Setting up the SDK with a random token and mock server. ClickUp's official mock server accepts random tokens as valid tokens. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Comments - Get Task Comments', () async { + final taskComments = + await clickUp.comments.getTaskComments(taskID: "a1b2c3"); + expect(taskComments.containsKey("comments"), true); + }); + test('Comments - Create Task Comment', () async { + final createdComment = await clickUp.comments.createTaskComment( + taskID: "a1b2c3", + comment: { + "comment_text": "Hi I am Emre", + "assignee": 123456, + "notify_all": true + }); + expect(createdComment.containsKey("id"), true); + }); + test('Comments - Create Task Comment - Invalid Data', () async { + expect( + () async => await clickUp.comments + .createTaskComment(taskID: "a1b2c3", comment: {}), + throwsA(isA())); + }); + + test('Comments - Get Chat View Comments - Last 25', () async { + final chatViewComments = + await clickUp.comments.getChatViewComments(viewID: "12345"); + + expect(chatViewComments.containsKey("comments"), true); + }); + test('Comments - Get Chat View Comments - Custom Range', () async { + final chatViewComments = await clickUp.comments + .getChatViewComments(viewID: "12345", start: 3, startID: "12345"); + + expect(chatViewComments.containsKey("comments"), true); + }); + test('Comments - Create Chat View Comment', () async { + final createdChatViewComment = await clickUp.comments + .createChatViewComment( + viewID: "12345", + comment: {"comment_text": "Hi I am Emre", "notify_all": true}); + + expect(createdChatViewComment.containsKey("id"), true); + }); + test('Comments - Create Chat View Comment - Invalid Data', () async { + expect( + () async => await clickUp.comments + .createChatViewComment(viewID: "12345", comment: {}), + throwsA(isA())); + }); + test('Comments - Get List Comments - Last 25', () async { + final listComments = + await clickUp.comments.getListComments(listID: 12345); + + expect(listComments.containsKey("comments"), true); + }); + test('Comments - Get List Comments - Custom Range', () async { + final listComments = await clickUp.comments + .getListComments(listID: 12345, start: 2, startID: "123"); + + expect(listComments.containsKey("comments"), true); + }); + + test('Comments - Create List Comment', () async { + final listComment = await clickUp.comments.createListComment( + listID: "12345", + comment: { + "comment_text": "Hi I am Emre", + "assignee": 123456, + "notify_all": true + }); + expect(listComment.containsKey("id"), true); + }); + test('Comments - Create List Comment - Invalid Data', () async { + expect( + () async => await clickUp.comments + .createListComment(listID: "12345", comment: {}), + throwsA(isA())); + }); + test('Comments - Update Comment', () async { + final updatedComment = await clickUp.comments.updateComment( + commentID: 1234, + comment: { + "comment_text": "Hi I am Emre", + "assignee": 123456, + "resolved": true + }); + expect(updatedComment.isEmpty, true); + }); + test('Comments - Update Comment - Invalid Data', () async { + expect( + () async => await clickUp.comments + .updateComment(commentID: 1234, comment: {}), + throwsA(isA())); + }); + test('Comments - Delete Comment', () async { + final deletedComment = + await clickUp.comments.deleteComment(commentID: 1234); + expect(deletedComment.isEmpty, true); + }); + }); +} diff --git a/test/integration/custom_fields_test.dart b/test/integration/custom_fields_test.dart new file mode 100644 index 0000000..8adc19c --- /dev/null +++ b/test/integration/custom_fields_test.dart @@ -0,0 +1,66 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:clickup_dart_sdk/src/core/clickup_exception.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + + group('Custom Fields Tests', () { + setUp(() async { + // Setting up the SDK with a random token and mock server. ClickUp's official mock server accepts random tokens as valid tokens. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + // Tests are run for just getting the fields and updating the URL field. Remaining field types are dependent on the model and all of the models actually return success. This means testing for only one field type should be enough. + test('Custom Fields - Get Accessible Custom Fields', () async { + final customFields = + await clickUp.customFields.getAccessibleCustomFields(listID: "1234"); + expect(customFields.containsKey("fields"), true); + }); + + test('Custom Fields - Set Custom Field Value - URL Custom Field', () async { + final customField = await clickUp.customFields.setCustomFieldValue( + fieldID: "1234", + taskID: "1234", + value: {"value": "https://ayazemre.com"}); + print(customField); + expect(customField.isEmpty, true); + }); + test( + 'Custom Fields - Set Custom Field Value - URL Custom Field - Custom Task ID', + () async { + final customField = await clickUp.customFields.setCustomFieldValue( + fieldID: "1234", + taskID: "1234", + value: {"value": "https://ayazemre.com"}, + customTaskID: true, + teamID: 1234); + expect(customField.isEmpty, true); + }); + test('Custom Fields - Set Custom Field Value - Wrong Data Model', () async { + expect( + () async => await clickUp.customFields.setCustomFieldValue( + fieldID: "1234", + taskID: "1234", + value: {"valeu": "https://ayazemre.com"}, + customTaskID: true, + teamID: 1234), + throwsA(isA())); + }); + test('Custom Fields - Remove Custom Field Value', () async { + final result = await clickUp.customFields + .removeCustomFieldValue(fieldID: "1234", taskID: "1234"); + expect(result.isEmpty, true); + }); + test('Custom Fields - Remove Custom Field Value - Custom Task ID', + () async { + final result = await clickUp.customFields.removeCustomFieldValue( + fieldID: "1234", taskID: "1234", customTaskID: true, teamID: 1234); + expect(result.isEmpty, true); + }); + }); +} diff --git a/test/integration/folders_test.dart b/test/integration/folders_test.dart new file mode 100644 index 0000000..51f94ea --- /dev/null +++ b/test/integration/folders_test.dart @@ -0,0 +1,50 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('Folders Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Folders - Get Folders', () async { + final folders = await clickUp.folders.getFolders(spaceID: 123); + expect(folders.containsKey("folders"), true); + }); + test('Folders - Get Folders: Include Archived', () async { + final folders = + await clickUp.folders.getFolders(spaceID: 123, includeArchived: true); + expect(folders.containsKey("folders"), true); + }); + test('Folders - Create Folder', () async { + final folder = + await clickUp.folders.createFolder(spaceID: 123, name: "Test Folder"); + expect(folder.containsKey("name") && folder.containsValue("Test Folder"), + true); + }); + test('Folders - Get Folder', () async { + final folder = await clickUp.folders.getFolder(folderID: 123); + expect(folder.containsKey("id"), true); + }); + test('Folders - Update Folder', () async { + final folder = await clickUp.folders + .updateFolder(folderID: 123, name: "Test Updated Folder"); + expect( + folder.containsKey("name") && + folder.containsValue("Test Updated Folder") && + folder.containsKey("id"), + true); + }); + test('Folders - Delete Folder', () async { + final folder = await clickUp.folders.deleteFolder(folderID: 123); + expect(folder.isEmpty, true); + }); + }); +} diff --git a/test/integration/goals_test.dart b/test/integration/goals_test.dart new file mode 100644 index 0000000..49da5f9 --- /dev/null +++ b/test/integration/goals_test.dart @@ -0,0 +1,93 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('Goals endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp(apiEndpoint: "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com")..initialize(authToken: token); + }); + + test('Goals - Get Goals', () async { + final goals = await clickUp.goals.getGoals(teamID: 0); + print(goals); + expect(goals.containsKey("goals"), true); + }); + test('Goals - Get Goals Include Completed', () async { + final goals = await clickUp.goals.getGoals(teamID: 0, includeCompleted: true); + print(goals); + expect(goals.containsKey("goals"), true); + }); + + test('Goals - Create Goal', () async { + final goal = await clickUp.goals.createGoal(teamID: 0, color: "red", description: "Hey", dueDate: 123456, goalName: "Test", multipleOwners: true, owners: [ + 123, + 456, + 789 + ]); + print(goal); + expect(goal.containsKey("goal"), true); + }); + test('Goals - Get Goal', () async { + final goal = await clickUp.goals.getGoal(goalID: 0); + print(goal); + expect(goal.containsKey("goal"), true); + }); + + test('Goals - Update Goal', () async { + final goal = await clickUp.goals.updateGoal(goalID: 0, color: "red", description: "Hey", dueDate: 123456, goalName: "Test", ownersToRemove: [ + 123, + 456 + ], ownersToAdd: [ + 789, + 146 + ]); + print(goal); + expect(goal.containsKey("goal"), true); + }); + + test('Goals - Delete Goal', () async { + final goal = await clickUp.goals.deleteGoal(goalID: 0); + print(goal); + expect(goal.isEmpty, true); + }); + test('Goals - Create Key Result', () async { + final keyResult = await clickUp.goals.createKeyResult(goalID: 0, goalName: "test", type: "number", unit: "km", stepsStart: 0, stepsEnd: 2, owners: [ + 0, + 1 + ], taskIDs: [ + "123", + "456" + ], listIDs: [ + "369", + "741" + ]); + print(keyResult); + expect(keyResult.containsKey("key_result"), true); + }); + + test('Goals - Edit Key Result', () async { + final keyResult = await clickUp.goals.editKeyResult(keyResultID: 0, goalName: "test", type: "number", unit: "km", note: "hey", stepsStart: 0, stepsCurrent: 1, stepsEnd: 2, owners: [ + 0, + 1 + ], taskIDs: [ + "123", + "456" + ], listIDs: [ + "369", + "741" + ]); + print(keyResult); + expect(keyResult.containsKey("key_result"), true); + }); + + test('Goals - Delete Key Result', () async { + final keyResult = await clickUp.goals.deleteKeyResult(keyResultID: 0); + print(keyResult); + expect(keyResult.isEmpty, true); + }); + }); +} diff --git a/test/integration/guests_test.dart b/test/integration/guests_test.dart new file mode 100644 index 0000000..5aa900a --- /dev/null +++ b/test/integration/guests_test.dart @@ -0,0 +1,75 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp(apiEndpoint: "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com")..initialize(authToken: token); + }); + + test('Guests - Invite Guest To Workspace', () async { + final guest = await clickUp.guests.inviteGuestToWorkspace(teamID: 1, email: "guest@example.com", canSeeTimeSpent: false, canCreateViews: false, canEditTags: false, canSeeTimeEstimated: true, customRoleID: 12345); + print(guest); + expect(guest.containsKey("team"), true); + }); + + test('Guests - Get Guest', () async { + final guest = await clickUp.guests.getGuest(teamID: 1, guestID: 2); + print(guest); + expect(guest.isEmpty, true); + }); + test('Guests - Edit Guest On Workspace', () async { + final guest = await clickUp.guests.editGuestOnWorkspace(teamID: 1, guestID: 2, username: "guest@example.com", canSeeTimeSpent: false, canCreateViews: false, canEditTags: false, canSeeTimeEstimated: true, customRoleID: 12345); + print(guest); + expect(guest.containsKey("guest"), true); + }); + + test('Guests - Remove Guest From Workspace', () async { + final guest = await clickUp.guests.removeGuestFromWorkspace(teamID: 1, guestID: 2); + print(guest); + expect(guest.containsKey("team"), true); + }); + test('Guests - Add Guest To Task', () async { + final guest = await clickUp.guests.addGuestToTask(taskID: "1234", guestID: 2456, permissionLevel: "read"); + print(guest); + expect(guest.containsKey("guest"), true); + }); + test('Guests - Add Guest To Task with Custom Task Id', () async { + final guest = await clickUp.guests.addGuestToTask(taskID: "1", guestID: 2, permissionLevel: "edit", includeShared: false, useCustomTaskID: true); + print(guest); + expect(guest.containsKey("guest"), true); + }); + test('Guests - Remove Guest From Task', () async { + final guest = await clickUp.guests.removeGuestFromTask(taskID: "1", guestID: 2, includeShared: false, useCustomTaskID: true); + print(guest); + expect(guest.containsKey("guest"), true); + }); + + test('Guests - Add Guest To List', () async { + final guest = await clickUp.guests.addGuestToList(listID: 1, guestID: 2, includeShared: false, permissionLevel: "read"); + print(guest); + expect(guest.containsKey("guest"), true); + }); + + test('Guests - Remove Guest From List', () async { + final guest = await clickUp.guests.removeGuestFromList(listID: 1, guestID: 2, includeShared: false); + print(guest); + expect(guest.containsKey("guest"), true); + }); + + test('Guests - Add Guest To Folder', () async { + final guest = await clickUp.guests.addGuestToFolder(folderID: 1, guestID: 2, includeShared: false, permissionLevel: "read"); + print(guest); + expect(guest.containsKey("guest"), true); + }); + test('Guests - Remove Guest From Folder', () async { + final guest = await clickUp.guests.removeGuestFromFolder(folderID: 1, guestID: 2, includeShared: false); + print(guest); + expect(guest.containsKey("guest"), true); + }); + }); +} diff --git a/test/integration/lists_test.dart b/test/integration/lists_test.dart new file mode 100644 index 0000000..015484f --- /dev/null +++ b/test/integration/lists_test.dart @@ -0,0 +1,31 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp(apiEndpoint: "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com")..initialize(authToken: token); + }); + + test('Lists - Get Lists', () async { + final lists = await clickUp.lists.getLists(folderID: 1, archived: false); + print(lists); + expect(lists.containsKey("lists"), true); + }); + + test('Lists - Create List', () async { + final lists = await clickUp.lists.createList(folderID: 1, listName: "test list"); + print(lists); + expect(lists.containsKey("id"), true); + }); + test('Lists - Create List with params', () async { + final lists = await clickUp.lists.createList(folderID: 1, listName: "test list", assignee: 1, content: "test"); + print(lists); + expect(lists.containsKey("id"), true); + }); + }); +} diff --git a/test/integration/members_test.dart b/test/integration/members_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/members_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/roles_test.dart b/test/integration/roles_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/roles_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/shared_hierarchy_test.dart b/test/integration/shared_hierarchy_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/shared_hierarchy_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/spaces_test.dart b/test/integration/spaces_test.dart new file mode 100644 index 0000000..a0765f8 --- /dev/null +++ b/test/integration/spaces_test.dart @@ -0,0 +1,49 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('Spaces Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Spaces - Get Spaces', () async { + final spaces = await clickUp.spaces.getSpaces(teamID: 123); + print(spaces); + expect(spaces.containsKey("spaces"), true); + }); + test('Spaces - Get Spaces: Include Archived', () async { + final spaces = + await clickUp.spaces.getSpaces(teamID: 123, includeArchived: true); + expect(spaces.containsKey("spaces"), true); + }); + test('Spaces - Create Space', () async { + final space = await clickUp.spaces.createSpace( + teamID: 123, spaceSchema: clickUp.spaces.sampleSpaceSchema); + expect(space.containsKey("features"), true); + }); + test('Spaces - Get Space', () async { + final space = await clickUp.spaces.getSpace(spaceID: 123); + expect(space.containsKey("features"), true); + }); + test('Spaces - Update Space', () async { + final space = + await clickUp.spaces.updateSpace(spaceID: 123, spaceSchema: { + ...clickUp.spaces.sampleSpaceSchema, + ...{"color": "blue", "private": false, "admin_can_manage": false} + }); + expect(space.containsKey("features"), true); + }); + test('Spaces - Delete Space', () async { + final space = await clickUp.spaces.deleteSpace(spaceID: 123); + expect(space.isEmpty, true); + }); + }); +} diff --git a/test/integration/tags_test.dart b/test/integration/tags_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/tags_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/task_checklists_test.dart b/test/integration/task_checklists_test.dart new file mode 100644 index 0000000..7525fab --- /dev/null +++ b/test/integration/task_checklists_test.dart @@ -0,0 +1,48 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('Task Checklists endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp(apiEndpoint: "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com")..initialize(authToken: token); + }); + + test('Task Checklists - Create a checklist', () async { + final checklist = await clickUp.taskChecklists.createChecklist(checklistName: "Test", taskID: "asdf123asde"); + print(checklist); + expect(checklist.containsKey("checklist"), true); + }); + + test('Task Checklists - Edit a checklist', () async { + final checklist = await clickUp.taskChecklists.editChecklist(checklistID: "b8a8-48d8-a0c6-b4200788a683", checklistName: "New Name", position: 0); + print(checklist); + expect(checklist.isEmpty, true); + }); + + test('Task Checklists - Delete a checklist', () async { + final checklist = await clickUp.taskChecklists.deleteChecklist(checklistID: "b8a8-48d8-a0c6-b4200788a683"); + print(checklist); + expect(checklist.isEmpty, true); + }); + test('Task Checklists - Create a checklist item', () async { + final checklist = await clickUp.taskChecklists.createChecklistItem(checklistName: "New Name", assignee: 123, checklistID: "b8a8-48d8-a0c6-b4200788a683"); + print(checklist); + expect(checklist.containsKey("checklist"), true); + }); + + test('Task Checklists - Edit a checklist item', () async { + final checklist = await clickUp.taskChecklists.editChecklistItem(checklistName: "New Name", assignee: "123", resolved: false, parent: "test", checklistItemID: "b8a8-48d8-a0c6-b4200788a683", checklistID: "b8a8-48d8-a0c6-b4200788a683"); + print(checklist); + expect(checklist.containsKey("checklist"), true); + }); + test('Task Checklists - Edit a checklist item', () async { + final checklist = await clickUp.taskChecklists.deleteChecklistItem(checklistItemID: "b8a8-48d8-a0c6-b4200788a683", checklistID: "b8a8-48d8-a0c6-b4200788a683"); + print(checklist); + expect(checklist.isEmpty, true); + }); + }); +} diff --git a/test/integration/task_relationships.dart b/test/integration/task_relationships.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/task_relationships.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/task_templates_test.dart b/test/integration/task_templates_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/task_templates_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/tasks_test.dart b/test/integration/tasks_test.dart new file mode 100644 index 0000000..9664ac6 --- /dev/null +++ b/test/integration/tasks_test.dart @@ -0,0 +1,91 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('Tasks Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Tasks - Get Tasks', () async { + final tasks = await clickUp.tasks.getTasks(listID: 1); + print(tasks); + expect(tasks.containsKey("tasks"), true); + }); + test('Tasks - Create Task', () async { + final task = await clickUp.tasks.createTask(listID: 1, taskDescription: { + "name": "", + "description": "", + "assignees": [], //List of integers + "tags": [], //List of Strings + "status": "", + "priority": 0, + "due_date": 0, + "due_date_time": false, + "time_estimate": 0, + "start_date": 0, + "start_date_time": false, + "notify_all": false, + "parent": "", + "links_to": "", + "check_required_custom_fields": false, + "custom_fields": [] // List of Maps + }); + print(task); + expect(task.containsKey("id"), true); + }); + test('Tasks - Get Specific Task ', () async { + final task = await clickUp.tasks.getTask(taskID: 1); + print(task); + expect(task.containsKey("id"), true); + }); + + test('Tasks - Update Task', () async { + final task = await clickUp.tasks.updateTask(taskID: 1, taskDescription: { + "name": "", + "description": "", + "status": "", + "priority": 0, + "due_date": 0, + "due_date_time": false, + "parent": "", + "time_estimate": 0, + "start_date": 0, + "start_date_time": false, + "assignees": {"add": [], "rem": []}, //List of integers + "archived": false + }); + print(task); + expect(task.containsKey("id"), true); + }); + test('Tasks - Delete Task', () async { + final task = await clickUp.tasks.deleteTask(taskID: 1); + print(task); + expect(task.isEmpty, true); + }); + test('Tasks - Get Filtered Team Tasks', () async { + final task = await clickUp.tasks.getFilteredTeamTasks(workspaceTeamID: 1); + print(task); + expect(task.containsKey("tasks"), true); + }); + test('Tasks - Get Tasks Time In Status', () async { + final task = await clickUp.tasks.getTasksTimeInStatus(taskID: "1"); + print(task); + expect(task.containsKey("current_status"), true); + }); + test('Tasks - Get Bulk Tasks Time In Status', () async { + final task = + await clickUp.tasks.getBulkTasksTimeInStatus(taskIDs: ["1", "2"]); + print(task); + final result = task.values.first as Map; + expect(result.containsKey("current_status"), true); + }); + }); +} diff --git a/test/integration/teams_test.dart b/test/integration/teams_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/teams_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/time_tracking_legacy_test.dart b/test/integration/time_tracking_legacy_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/time_tracking_legacy_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/time_tracking_v2_test.dart b/test/integration/time_tracking_v2_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/time_tracking_v2_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/users_test.dart b/test/integration/users_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/users_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/views_test.dart b/test/integration/views_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/views_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +} diff --git a/test/integration/webhooks_test.dart b/test/integration/webhooks_test.dart new file mode 100644 index 0000000..c01774d --- /dev/null +++ b/test/integration/webhooks_test.dart @@ -0,0 +1,23 @@ +import 'package:clickup_dart_sdk/clickup_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + late String token; + late ClickUp clickUp; + group('API endpoint Tests', () { + setUp(() async { + // Additional setup goes here. + token = "pk_qwerty123456"; + clickUp = ClickUp( + apiEndpoint: + "https://a00fb6e0-339c-4201-972f-503b9932d17a.remockly.com") + ..initialize(authToken: token); + }); + + test('Authorization - Get Authorized User', () async { + final user = await clickUp.auth.getAuthorizedUser(); + print(user); + expect(user.containsKey("user"), true); + }); + }); +}