diff --git a/Changelog.md b/Changelog.md index fd4b918..5ee1961 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,15 @@ # Changelog *Below is the version history of [TrelloDotNet](https://github.com/rwjdk/TrelloDotNet) (An wrapper of the Trello API)* +## 1.9.7 (23rd of December 2023) +#### TrelloClient +- Added a set of handy Checklist Extensions on single and collection of checklists (`GetNumberOfItems`, `GetNumberOfCompletedItems`,`GetNumberOfIncompleteItems`, `IsAllComplete`,`IsAnyIncomplete`) +- Added advanced version of [`MoveCardToListAsync`](https://github.com/rwjdk/TrelloDotNet/wiki/MoveCardToListAsync) that accept additional options for the move (Position and NamedPosition) +- Added [`MoveCardToBoard`](https://github.com/rwjdk/TrelloDotNet/wiki/MoveCardToBoard) +- Added `GetMemberOption` overloads to the various member-get methods +- Added Member Properties `Email` and `MemberType` +- Added Properties on Member to the various Avatar URLs (30x30, 50x50, 170x170 pixels and the original image) + ## 1.9.6 (22nd of December 2023) #### General - Better nuget description and tags diff --git a/TrelloDotNet/TrelloDotNet.sln.DotSettings b/TrelloDotNet/TrelloDotNet.sln.DotSettings index 5045781..738c512 100644 --- a/TrelloDotNet/TrelloDotNet.sln.DotSettings +++ b/TrelloDotNet/TrelloDotNet.sln.DotSettings @@ -1,4 +1,5 @@  + True True True True diff --git a/TrelloDotNet/TrelloDotNet/Model/Checklist.cs b/TrelloDotNet/TrelloDotNet/Model/Checklist.cs index df0c401..3099d58 100644 --- a/TrelloDotNet/TrelloDotNet/Model/Checklist.cs +++ b/TrelloDotNet/TrelloDotNet/Model/Checklist.cs @@ -37,7 +37,7 @@ public class Checklist [JsonPropertyName("pos")] [QueryParameter] public decimal Position { get; set; } - + /// /// The items of the Checklist /// diff --git a/TrelloDotNet/TrelloDotNet/Model/ChecklistExtensions.cs b/TrelloDotNet/TrelloDotNet/Model/ChecklistExtensions.cs new file mode 100644 index 0000000..b035e9a --- /dev/null +++ b/TrelloDotNet/TrelloDotNet/Model/ChecklistExtensions.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Linq; + +namespace TrelloDotNet.Model +{ + /// + /// A set of handy extension methods for Checklists + /// + public static class ChecklistExtensions + { + /// + /// Get Number of Items on the Checklist regardless of state + /// + /// Number of Items + public static int GetNumberOfItems(this Checklist checklist) + { + return checklist.Items.Count; + } + + /// + /// Get the Number of Completed items on the Checklist + /// + /// Number of Completed Items + public static int GetNumberOfCompletedItems(this Checklist checklist) + { + return checklist.Items.Count(x => x.State == ChecklistItemState.Complete); + } + + /// + /// Get the Number of Incomplete items on the Checklist + /// + /// Number of Completed Items + public static int GetNumberOfIncompleteItems(this Checklist checklist) + { + return checklist.Items.Count(x => x.State == ChecklistItemState.Incomplete); + } + + /// + /// Returns if all items on the Checklist is complete + /// + /// True if all Items are complete + public static bool IsAllComplete(this Checklist checklist) + { + return checklist.Items.All(x => x.State == ChecklistItemState.Complete); + } + + /// + /// Returns if any of the checklist items ar not yet complete + /// + /// True if on or more is incomplete + public static bool IsAnyIncomplete(this Checklist checklist) + { + return checklist.Items.Any(x => x.State != ChecklistItemState.Complete); + } + + /// + /// Get Number of Items across a collection of Checklists regardless of state + /// + /// Number of Items + public static int GetNumberOfItems(this IEnumerable checklists) + { + return checklists.Sum(x => x.GetNumberOfItems()); + } + + /// + /// Get the Number of Completed items across a collection of Checklists + /// + /// Number of Completed Items + public static int GetNumberOfCompletedItems(this IEnumerable checklists) + { + return checklists.Sum(x => x.GetNumberOfCompletedItems()); + } + + /// + /// Get the Number of Incomplete items across a collection of Checklists + /// + /// Number of Completed Items + public static int GetNumberOfIncompleteItems(this IEnumerable checklists) + { + return checklists.Sum(x => x.GetNumberOfIncompleteItems()); + } + + /// + /// Returns if all items on the Checklist is complete + /// + /// True if all Items are complete + public static bool IsAllComplete(this IEnumerable checklists) + { + return checklists.All(x => x.IsAllComplete()); + } + + /// + /// Returns if any of the checklist items ar not yet complete + /// + /// True if on or more is incomplete + public static bool IsAnyIncomplete(this IEnumerable checklists) + { + return checklists.Any(x => x.IsAnyIncomplete()); + } + } +} \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/Model/Member.cs b/TrelloDotNet/TrelloDotNet/Model/Member.cs index 4302d44..40e4b26 100644 --- a/TrelloDotNet/TrelloDotNet/Model/Member.cs +++ b/TrelloDotNet/TrelloDotNet/Model/Member.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Text.Json.Serialization; +using TrelloDotNet.Control; namespace TrelloDotNet.Model { @@ -38,12 +39,32 @@ public class Member public string Initials { get; private set; } /// - /// The url of this member's avatar + /// The base url of this member's avatar /// [JsonPropertyName("avatarUrl")] [JsonInclude] public string AvatarUrl { get; private set; } + /// + /// 30x30 Pixel version of the Members Avatar Image + /// + public string AvatarUrl30 => AvatarUrl != null ? $"{AvatarUrl}/30.png" : null; + + /// + /// 50x50 Pixel version of the Members Avatar Image + /// + public string AvatarUrl50 => AvatarUrl != null ? $"{AvatarUrl}/50.png" : null; + + /// + /// 170x170 Pixel version of the Members Avatar Image + /// + public string AvatarUrl170 => AvatarUrl != null ? $"{AvatarUrl}/170.png" : null; + + /// + /// Original version of the Members Avatar Image + /// + public string AvatarUrlOriginal => AvatarUrl != null ? $"{AvatarUrl}/original.png" : null; + /// /// Whether the user has confirmed their email address for their account. /// @@ -51,6 +72,21 @@ public class Member [JsonInclude] public bool Confirmed { get; private set; } + /// + /// The Email of the member (only populated if field is included in GetMemberOptions) + /// + [JsonPropertyName("email")] + [JsonInclude] + public string Email { get; private set; } + + /// + /// The Type of the Members (admin, normal, observer) [only populated if field is included in GetMemberOptions] + /// + [JsonPropertyName("memberType")] + [JsonInclude] + [JsonConverter(typeof(EnumViaJsonPropertyConverter))] + public MembershipType MemberType { get; private set; } + internal static Member CreateDummy() { return new Member() diff --git a/TrelloDotNet/TrelloDotNet/Model/Options/GetMemberOptions/GetMemberOptions.cs b/TrelloDotNet/TrelloDotNet/Model/Options/GetMemberOptions/GetMemberOptions.cs new file mode 100644 index 0000000..92e6082 --- /dev/null +++ b/TrelloDotNet/TrelloDotNet/Model/Options/GetMemberOptions/GetMemberOptions.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace TrelloDotNet.Model.Options.GetMemberOptions +{ + /// + /// Options when retrieving members + /// + public class GetMemberOptions + { + /// + /// all or a comma-separated list of fields. + /// + public MemberFields MemberFields { get; set; } + + internal QueryParameter[] GetParameters() + { + List parameters = new List(); + if (MemberFields != null) + { + parameters.Add(new QueryParameter("fields", string.Join(",", MemberFields.Fields))); + } + + return parameters.ToArray(); + } + } +} \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/Model/Options/MemberFieldsType.cs b/TrelloDotNet/TrelloDotNet/Model/Options/MemberFieldsType.cs index 2ccca3f..a741d1d 100644 --- a/TrelloDotNet/TrelloDotNet/Model/Options/MemberFieldsType.cs +++ b/TrelloDotNet/TrelloDotNet/Model/Options/MemberFieldsType.cs @@ -10,27 +10,36 @@ public enum MemberFieldsType /// /// The full name related to the account, if it is public. /// - [JsonPropertyName("fullName")] - FullName, + [JsonPropertyName("fullName")] FullName, + /// /// Username of the Member /// - [JsonPropertyName("username")] - Username, + [JsonPropertyName("username")] Username, + /// /// The initials related to the account, if it is public. /// - [JsonPropertyName("initials")] - Initials, + [JsonPropertyName("initials")] Initials, + /// /// The url of this member's avatar /// - [JsonPropertyName("avatarUrl")] - AvatarUrl, + [JsonPropertyName("avatarUrl")] AvatarUrl, + /// /// Whether the user has confirmed their email address for their account. /// - [JsonPropertyName("confirmed")] - Confirmed, + [JsonPropertyName("confirmed")] Confirmed, + + /// + /// Email of Member + /// + [JsonPropertyName("email")] Email, + + /// + /// Type Member (admin, normal, observer) + /// + [JsonPropertyName("memberType")] MemberType, } } \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptions.cs b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptions.cs new file mode 100644 index 0000000..f944338 --- /dev/null +++ b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptions.cs @@ -0,0 +1,43 @@ +namespace TrelloDotNet.Model.Options.MoveCardToBoardOptions +{ + /// + /// Options when moving a card to a new board + /// + public class MoveCardToBoardOptions + { + /// + /// Id of a List on the new Board (if not specified card will be moved to the first list on the board) + /// + public string NewListId { get; set; } + + /// + /// Position of the card on the new list (Will not be used if NamedPosition is used) + /// + public decimal? PositionOnNewList { get; set; } + + /// + /// Named position of the card on the new list (will ignore position given in these options if any) + /// + public NamedPosition? NamedPositionOnNewList { get; set; } + + /// + /// Define what should happen to Labels on the Card (Default = 'MigrateToLabelsOfSameNameAndColorAndCreateMissing') + /// + public MoveCardToBoardOptionsLabelOptions LabelOptions { get; set; } = MoveCardToBoardOptionsLabelOptions.MigrateToLabelsOfSameNameAndColorAndCreateMissing; + + /// + /// Define what should happen to Members on the Card (Default = 'KeepMembersAlsoOnNewBoardAndRemoveRest') + /// + public MoveCardToBoardOptionsMemberOptions MemberOptions { get; set; } = MoveCardToBoardOptionsMemberOptions.KeepMembersAlsoOnNewBoardAndRemoveRest; + + /// + /// If the Start Date of the Card should be removed (Default = False) + /// + public bool RemoveStartDate { get; set; } + + /// + /// If the Due Date of the Card should be removed (Default = False) + /// + public bool RemoveDueDate { get; set; } + } +} \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptionsLabelOptions.cs b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptionsLabelOptions.cs new file mode 100644 index 0000000..5f1bef3 --- /dev/null +++ b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptionsLabelOptions.cs @@ -0,0 +1,33 @@ +namespace TrelloDotNet.Model.Options.MoveCardToBoardOptions +{ + /// + /// Label options when moving a Card to another board + /// + public enum MoveCardToBoardOptionsLabelOptions + { + /// + /// Migrate Labels with the same color and name, and create those missing as labels on the new board + /// + MigrateToLabelsOfSameNameAndColorAndCreateMissing, + + /// + /// Migrate Labels with the same color and name, and remove all labels that does not exist on the new board + /// + MigrateToLabelsOfSameNameAndColorAndRemoveMissing, + + /// + /// Migrate Labels with the same name (allow color change), and create those missing as labels on the new board + /// + MigrateToLabelsOfSameNameAndCreateMissing, + + /// + /// Migrate Labels with the same name (allow color change), and remove all labels that does not exist on the new board + /// + MigrateToLabelsOfSameNameAndRemoveMissing, + + /// + /// Remove all labels before move to new board + /// + RemoveAllLabelsOnCard, + } +} \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptionsMemberOptions.cs b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptionsMemberOptions.cs new file mode 100644 index 0000000..a8573d4 --- /dev/null +++ b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToBoardOptions/MoveCardToBoardOptionsMemberOptions.cs @@ -0,0 +1,18 @@ +namespace TrelloDotNet.Model.Options.MoveCardToBoardOptions +{ + /// + /// Member options when moving a Card to another board + /// + public enum MoveCardToBoardOptionsMemberOptions + { + /// + /// Keep the members on the card that is also members of the new board, and remove the rest + /// + KeepMembersAlsoOnNewBoardAndRemoveRest, + + /// + /// Remove all members on the board + /// + RemoveAllMembersOnCard + } +} \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToListOptions/MoveCardToListOptions.cs b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToListOptions/MoveCardToListOptions.cs new file mode 100644 index 0000000..cf4be8c --- /dev/null +++ b/TrelloDotNet/TrelloDotNet/Model/Options/MoveCardToListOptions/MoveCardToListOptions.cs @@ -0,0 +1,18 @@ +namespace TrelloDotNet.Model.Options.MoveCardToListOptions +{ + /// + /// Option of the Move + /// + public class MoveCardToListOptions + { + /// + /// Position of the card on the new list (Will not be used if NamedPosition is used) + /// + public decimal? PositionOnNewList { get; set; } + + /// + /// Named position of the card on the new list (will ignore position given in these options if any) + /// + public NamedPosition? NamedPositionOnNewList { get; set; } + } +} \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/TrelloClient.Cards.cs b/TrelloDotNet/TrelloDotNet/TrelloClient.Cards.cs index 39f4e24..59de472 100644 --- a/TrelloDotNet/TrelloDotNet/TrelloClient.Cards.cs +++ b/TrelloDotNet/TrelloDotNet/TrelloClient.Cards.cs @@ -4,12 +4,12 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using TrelloDotNet.AutomationEngine.Model; -using TrelloDotNet.AutomationEngine.Model.Actions; using TrelloDotNet.Control; using TrelloDotNet.Model; using TrelloDotNet.Model.Options; using TrelloDotNet.Model.Options.GetCardOptions; +using TrelloDotNet.Model.Options.MoveCardToBoardOptions; +using TrelloDotNet.Model.Options.MoveCardToListOptions; namespace TrelloDotNet { @@ -85,8 +85,10 @@ private static string GeneratePayloadForCoverUpdate(CardCover cardCover, List> GetCardsOnBoardAsync(string boardId, CancellationT return await _apiRequestController.Get>(GetUrlBuilder.GetCardsOnBoard(boardId), cancellationToken, new QueryParameter("customFieldItems", Options.IncludeCustomFieldsInCardGetMethods), new QueryParameter("attachments", Options.IncludeAttachmentsInCardGetMethods) - ); + ); } /// @@ -316,6 +318,37 @@ public async Task MoveCardToListAsync(string cardId, string newListId, Can }, cancellationToken); } + /// + /// Move a Card to a new list on the same board + /// + /// Id of the Card + /// Id of the List you wish to move it to + /// Additional optional Options for the Move + /// Cancellation Token + /// + public async Task MoveCardToListAsync(string cardId, string newListId, MoveCardToListOptions options, CancellationToken cancellationToken = default) + { + var parameters = new List { new QueryParameter(CardFieldsType.ListId.GetJsonPropertyName(), newListId) }; + if (options.NamedPositionOnNewList.HasValue) + { + switch (options.NamedPositionOnNewList.Value) + { + case NamedPosition.Top: + parameters.Add(new QueryParameter("pos", "top")); + break; + case NamedPosition.Bottom: + parameters.Add(new QueryParameter("pos", "bottom")); + break; + } + } + else if (options.PositionOnNewList.HasValue) + { + parameters.Add(new QueryParameter(CardFieldsType.Position.GetJsonPropertyName(), options.PositionOnNewList.Value)); + } + + return await UpdateCardAsync(cardId, parameters, cancellationToken); + } + /// /// Update one or more specific fields on a card (compared to a full update of all fields with UpdateCard) /// @@ -336,5 +369,190 @@ public async Task UpdateCardAsync(string cardId, List para //Special Cover Card return await _apiRequestController.Put($"{UrlPaths.Cards}/{cardId}", cancellationToken, parameters.ToArray()); } + + /// + /// Move the Card to the top of its current list + /// + /// Id of the Card + /// Cancellation Token + /// The Card + public async Task MoveCardToTopOfCurrentListAsync(string cardId, CancellationToken cancellationToken = default) + { + return await UpdateCardAsync(cardId, new List + { + new QueryParameter(CardFieldsType.Position.GetJsonPropertyName(), "top") + }, cancellationToken); + } + + /// + /// Move the Card to the bottom of its current list + /// + /// Id of the Card + /// Cancellation Token + /// The Card + public async Task MoveCardToBottomOfCurrentListAsync(string cardId, CancellationToken cancellationToken = default) + { + return await UpdateCardAsync(cardId, new List + { + new QueryParameter(CardFieldsType.Position.GetJsonPropertyName(), "bottom") + }, cancellationToken); + } + + /// + /// Move a Card to another board + /// + /// The Id of the Card to Move + /// The ID of the New Board that the card should be moved to + /// Additional Options for the move like what list the card should end up on the new board and what happens to labels and members + /// Cancellation Token + /// + public async Task MoveCardToBoard(string cardId, string newBoardId, MoveCardToBoardOptions options, CancellationToken cancellationToken = default) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options), "You need to pass an options object to confirm the various options that are invovled with moving a card between boards"); + } + + List parameters = new List { new QueryParameter(CardFieldsType.BoardId.GetJsonPropertyName(), newBoardId) }; + var newListId = options.NewListId; + if (string.IsNullOrWhiteSpace(newListId)) + { + //No list specified, so we need to find the first list on the board + newListId = (await GetListsOnBoardAsync(newBoardId, cancellationToken)).OrderBy(x => x.Position).FirstOrDefault()?.Id; + } + + parameters.Add(new QueryParameter(CardFieldsType.ListId.GetJsonPropertyName(), newListId)); + + if (options.NamedPositionOnNewList.HasValue) + { + switch (options.NamedPositionOnNewList.Value) + { + case NamedPosition.Top: + parameters.Add(new QueryParameter("pos", "top")); + break; + case NamedPosition.Bottom: + parameters.Add(new QueryParameter("pos", "bottom")); + break; + } + } + else if (options.PositionOnNewList.HasValue) + { + parameters.Add(new QueryParameter(CardFieldsType.Position.GetJsonPropertyName(), options.PositionOnNewList.Value)); + } + + Card card = await GetCardAsync(cardId, new GetCardOptions + { + CardFields = new CardFields(CardFieldsType.MemberIds, CardFieldsType.LabelIds, CardFieldsType.Labels) + }, cancellationToken); + + switch (options.MemberOptions) + { + case MoveCardToBoardOptionsMemberOptions.KeepMembersAlsoOnNewBoardAndRemoveRest: + var existingMemberIdsOnNewBoard = (await GetMembersOfBoardAsync(newBoardId, cancellationToken)).Select(x => x.Id); + card.MemberIds = card.MemberIds.Intersect(existingMemberIdsOnNewBoard).ToList(); + break; + case MoveCardToBoardOptionsMemberOptions.RemoveAllMembersOnCard: + card.MemberIds.Clear(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (card.LabelIds.Any()) + { + card.LabelIds.Clear(); + switch (options.LabelOptions) + { + case MoveCardToBoardOptionsLabelOptions.MigrateToLabelsOfSameNameAndColorAndCreateMissing: + { + var existingLabels = await GetLabelsOfBoardAsync(newBoardId, cancellationToken); + foreach (Label cardLabel in card.Labels) + { + Label existingLabel = existingLabels.FirstOrDefault(x => x.Name == cardLabel.Name && x.Color == cardLabel.Color); + if (existingLabel != null) + { + card.LabelIds.Add(existingLabel.Id); + } + else + { + //Label need to be added + Label newLabel = await AddLabelAsync(new Label(newBoardId, cardLabel.Name, cardLabel.Color), cancellationToken); + card.LabelIds.Add(newLabel.Id); + } + } + + break; + } + case MoveCardToBoardOptionsLabelOptions.MigrateToLabelsOfSameNameAndColorAndRemoveMissing: + { + var existingLabels = await GetLabelsOfBoardAsync(newBoardId, cancellationToken); + foreach (Label cardLabel in card.Labels) + { + Label existingLabel = existingLabels.FirstOrDefault(x => x.Name == cardLabel.Name && x.Color == cardLabel.Color); + if (existingLabel != null) + { + card.LabelIds.Add(existingLabel.Id); + } + } + + break; + } + case MoveCardToBoardOptionsLabelOptions.MigrateToLabelsOfSameNameAndCreateMissing: + { + var existingLabels = await GetLabelsOfBoardAsync(newBoardId, cancellationToken); + foreach (Label cardLabel in card.Labels) + { + Label existingLabel = existingLabels.FirstOrDefault(x => x.Name == cardLabel.Name); + if (existingLabel != null) + { + card.LabelIds.Add(existingLabel.Id); + } + else + { + //Label need to be added + Label newLabel = await AddLabelAsync(new Label(newBoardId, cardLabel.Name, cardLabel.Color), cancellationToken); + card.LabelIds.Add(newLabel.Id); + } + } + + break; + } + case MoveCardToBoardOptionsLabelOptions.MigrateToLabelsOfSameNameAndRemoveMissing: + { + var existingLabels = await GetLabelsOfBoardAsync(newBoardId, cancellationToken); + foreach (Label cardLabel in card.Labels) + { + Label existingLabel = existingLabels.FirstOrDefault(x => x.Name == cardLabel.Name); + if (existingLabel != null) + { + card.LabelIds.Add(existingLabel.Id); + } + } + + break; + } + case MoveCardToBoardOptionsLabelOptions.RemoveAllLabelsOnCard: + //No more Work needed + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + parameters.Add(new QueryParameter(CardFieldsType.LabelIds.GetJsonPropertyName(), card.LabelIds)); + parameters.Add(new QueryParameter(CardFieldsType.MemberIds.GetJsonPropertyName(), card.MemberIds)); + + if (options.RemoveDueDate) + { + parameters.Add(new QueryParameter(CardFieldsType.Due.GetJsonPropertyName(), (DateTimeOffset?)null)); + } + + if (options.RemoveStartDate) + { + parameters.Add(new QueryParameter(CardFieldsType.Start.GetJsonPropertyName(), (DateTimeOffset?)null)); + } + + return await UpdateCardAsync(cardId, parameters, cancellationToken); + } } } \ No newline at end of file diff --git a/TrelloDotNet/TrelloDotNet/TrelloClient.Members.cs b/TrelloDotNet/TrelloDotNet/TrelloClient.Members.cs index b2b186f..7d67345 100644 --- a/TrelloDotNet/TrelloDotNet/TrelloClient.Members.cs +++ b/TrelloDotNet/TrelloDotNet/TrelloClient.Members.cs @@ -5,6 +5,7 @@ using TrelloDotNet.Control; using TrelloDotNet.Model; using TrelloDotNet.Model.Options; +using TrelloDotNet.Model.Options.GetMemberOptions; namespace TrelloDotNet { @@ -21,6 +22,18 @@ public async Task> GetMembersOfBoardAsync(string boardId, Cancellat return await _apiRequestController.Get>(GetUrlBuilder.GetMembersOfBoard(boardId), cancellationToken); } + /// + /// Get the Members (users) of a board + /// + /// Id of the Board (in its long or short version) + /// Option for what data to include on the Member + /// Cancellation Token + /// List of Members + public async Task> GetMembersOfBoardAsync(string boardId, GetMemberOptions options, CancellationToken cancellationToken = default) + { + return await _apiRequestController.Get>(GetUrlBuilder.GetMembersOfBoard(boardId), cancellationToken, options.GetParameters()); + } + /// /// Get the Members (users) who voted on a Card /// @@ -32,6 +45,18 @@ public async Task> GetMembersWhoVotedOnCardAsync(string cardId, Can return await _apiRequestController.Get>(GetUrlBuilder.GetMembersWhoVotedOnOfCard(cardId), cancellationToken); } + /// + /// Get the Members (users) who voted on a Card + /// + /// Id of the Card + /// Option for what data to include on the Member + /// Cancellation Token + /// List of Members who voted + public async Task> GetMembersWhoVotedOnCardAsync(string cardId, GetMemberOptions options, CancellationToken cancellationToken = default) + { + return await _apiRequestController.Get>(GetUrlBuilder.GetMembersWhoVotedOnOfCard(cardId), cancellationToken, options.GetParameters()); + } + /// /// Get the Members (users) of a Card /// @@ -43,6 +68,18 @@ public async Task> GetMembersOfCardAsync(string cardId, Cancellatio return await _apiRequestController.Get>(GetUrlBuilder.GetMembersOfCard(cardId), cancellationToken); } + /// + /// Get the Members (users) of a Card + /// + /// Id of the Card + /// Option for what data to include on the Member + /// Cancellation Token + /// List of Members + public async Task> GetMembersOfCardAsync(string cardId, GetMemberOptions options, CancellationToken cancellationToken = default) + { + return await _apiRequestController.Get>(GetUrlBuilder.GetMembersOfCard(cardId), cancellationToken, options.GetParameters()); + } + /// /// Get a Member with a specific Id /// @@ -84,7 +121,7 @@ public async Task AddMembersToCardAsync(string cardId, CancellationToken c card.MemberIds.AddRange(missing); return await UpdateCardAsync(cardId, new List { - new QueryParameter(CardFieldsType.MemberIds.GetJsonPropertyName(), card.MemberIds) + new QueryParameter(CardFieldsType.MemberIds.GetJsonPropertyName(), card.MemberIds) }, cancellationToken); } @@ -117,7 +154,7 @@ public async Task RemoveMembersFromCardAsync(string cardId, CancellationTo card.MemberIds = card.MemberIds.Except(toRemove).ToList(); return await UpdateCardAsync(cardId, new List { - new QueryParameter(CardFieldsType.MemberIds.GetJsonPropertyName(), card.MemberIds) + new QueryParameter(CardFieldsType.MemberIds.GetJsonPropertyName(), card.MemberIds) }, cancellationToken); } @@ -183,6 +220,17 @@ public async Task GetTokenMemberAsync(CancellationToken cancellationToke return await _apiRequestController.Get(GetUrlBuilder.GetTokenMember(_apiRequestController.Token), cancellationToken); } + /// + /// Get information about the Member that owns the token used by this TrelloClient + /// Option for what data to include on the Member + /// Cancellation Token + /// + /// The Member + public async Task GetTokenMemberAsync(GetMemberOptions options, CancellationToken cancellationToken = default) + { + return await _apiRequestController.Get(GetUrlBuilder.GetTokenMember(_apiRequestController.Token), cancellationToken, options.GetParameters()); + } + /// /// Get the Members (users) of an Organization (aka Workspace) /// @@ -194,6 +242,18 @@ public async Task> GetMembersOfOrganizationAsync(string organizatio return await _apiRequestController.Get>(GetUrlBuilder.GetMembersOfOrganization(organizationId), cancellationToken); } + /// + /// Get the Members (users) of an Organization (aka Workspace) + /// + /// Id of the Organization + /// Option for what data to include on the Member + /// Cancellation Token + /// List of Members + public async Task> GetMembersOfOrganizationAsync(string organizationId, GetMemberOptions options, CancellationToken cancellationToken = default) + { + return await _apiRequestController.Get>(GetUrlBuilder.GetMembersOfOrganization(organizationId), cancellationToken, options.GetParameters()); + } + /// /// Add a member vote to a card /// diff --git a/TrelloDotNet/TrelloDotNet/TrelloDotNet.csproj b/TrelloDotNet/TrelloDotNet/TrelloDotNet.csproj index 47f4df9..328b852 100644 --- a/TrelloDotNet/TrelloDotNet/TrelloDotNet.csproj +++ b/TrelloDotNet/TrelloDotNet/TrelloDotNet.csproj @@ -13,7 +13,7 @@ https://github.com/rwjdk/TrelloDotNet/wiki trello.png trello api rest .NET8 .NET7 .NET6 dotNet crud wrapper webhook automation - 1.9.6 + 1.9.7 RWJDK MIT https://github.com/rwjdk/TrelloDotNet/blob/main/Changelog.md