• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rwjdk / TrelloDotNet / 8898465898

30 Apr 2024 04:37PM UTC coverage: 62.094% (-0.1%) from 62.212%
8898465898

push

github

web-flow
#30 Fixed (#31)

890 of 1777 branches covered (50.08%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 1 file covered. (100.0%)

7 existing lines in 3 files now uncovered.

2319 of 3391 relevant lines covered (68.39%)

52.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.04
/TrelloDotNet/TrelloDotNet/Control/ApiRequestController.cs
1
using System;
2
using System.Net;
3
using System.Net.Http;
4
using System.Net.Http.Headers;
5
using System.Text;
6
using System.Text.Json;
7
using System.Threading;
8
using System.Threading.Tasks;
9
using TrelloDotNet.Model;
10

11
namespace TrelloDotNet.Control
12
{
13
    internal class ApiRequestController
14
    {
15
        private const string BaseUrl = "https://api.trello.com/1/";
16
        private readonly HttpClient _httpClient;
17
        private readonly string _apiKey;
18
        private readonly string _token;
19
        private readonly TrelloClient _client;
20

21
        internal ApiRequestController(HttpClient httpClient, string apiKey, string token, TrelloClient client)
191✔
22
        {
23
            _httpClient = httpClient;
191✔
24
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
191✔
25
            _apiKey = apiKey;
191✔
26
            _token = token;
191✔
27
            _client = client;
191✔
28
        }
191✔
29

30
        public string Token => _token;
21✔
31

32
        internal async Task<T> Get<T>(string suffix, CancellationToken cancellationToken, params QueryParameter[] parameters)
33
        {
34
            string json = await Get(suffix, cancellationToken, 0, parameters);
307✔
35
            var @object = JsonSerializer.Deserialize<T>(json);
307✔
36
            return @object;
307✔
37
        }
307✔
38

39
        internal async Task<string> Get(string suffix, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
40
        {
41
            var uri = BuildUri(suffix, parameters);
348✔
42
            var response = await _httpClient.GetAsync(uri, cancellationToken);
348✔
43
            var responseContent = await response.Content.ReadAsStringAsync();
348✔
44
            if (response.StatusCode != HttpStatusCode.OK)
348✔
45
            {
46
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => Get(suffix, cancellationToken, retry, parameters), retryCount, cancellationToken);
76✔
47
            }
48
            return responseContent; //Content is assumed JSON
308✔
49
        }
344✔
50

51
        internal async Task<T> Post<T>(string suffix, CancellationToken cancellationToken, params QueryParameter[] parameters)
52
        {
53
            string json = await Post(suffix, cancellationToken, 0, parameters);
251✔
54
            var @object = JsonSerializer.Deserialize<T>(json);
251✔
55
            return @object;
251✔
56
        }
251✔
57

58
        internal async Task<T> PostWithAttachmentFileUpload<T>(string suffix, AttachmentFileUpload attachmentFile, CancellationToken cancellationToken, params QueryParameter[] parameters)
59
        {
60
            string json = await PostWithAttachmentFileUpload(suffix, attachmentFile, cancellationToken, 0, parameters);
1✔
61
            var @object = JsonSerializer.Deserialize<T>(json);
1✔
62
            return @object;
1✔
63
        }
1✔
64

65
        internal async Task<string> PostWithAttachmentFileUpload(string suffix, AttachmentFileUpload attachmentFile, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
66
        {
67
            var uri = BuildUri(suffix, parameters);
1✔
68
            using (var multipartFormContent = new MultipartFormDataContent())
1✔
69
            {
70
                multipartFormContent.Add(new StreamContent(attachmentFile.Stream), name: "file", fileName: attachmentFile.Filename);
1✔
71
                var response = await _httpClient.PostAsync(uri, multipartFormContent, cancellationToken);
1✔
72
                var responseContent = await response.Content.ReadAsStringAsync();
1✔
73
                if (response.StatusCode != HttpStatusCode.OK)
1!
74
                {
UNCOV
75
                    return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => PostWithAttachmentFileUpload(suffix, attachmentFile, cancellationToken, retry, parameters), retryCount, cancellationToken);
×
76
                }
77
                return responseContent; //Content is assumed JSON
1✔
78
            }
79
        }
1✔
80

81
        internal async Task<string> Post(string suffix, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
82
        {
83
            var uri = BuildUri(suffix, parameters);
261✔
84
            var response = await _httpClient.PostAsync(uri, null, cancellationToken);
261✔
85
            var content = await response.Content.ReadAsStringAsync();
261✔
86
            if (response.StatusCode != HttpStatusCode.OK)
261✔
87
            {
88
                return await PreformRetryIfNeededOrThrow(uri, content, retry => Post(suffix, cancellationToken, retry, parameters), retryCount, cancellationToken);
15✔
89
            }
90
            return content; //Content is assumed JSON
253✔
91
        }
260✔
92

93
        internal async Task<T> Put<T>(string suffix, CancellationToken cancellationToken, params QueryParameter[] parameters)
94
        {
95
            string json = await Put(suffix, cancellationToken, 0, parameters);
74✔
96
            var @object = JsonSerializer.Deserialize<T>(json);
74✔
97
            return @object;
74✔
98
        }
74✔
99

100
        internal async Task<string> Put(string suffix, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
101
        {
102
            var uri = BuildUri(suffix, parameters);
83✔
103
            var response = await _httpClient.PutAsync(uri, null, cancellationToken);
83✔
104
            var responseContent = await response.Content.ReadAsStringAsync();
83✔
105
            if (response.StatusCode != HttpStatusCode.OK)
83✔
106
            {
107
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => Put(suffix, cancellationToken, retry, parameters), retryCount, cancellationToken);
9✔
108
            }
109
            return responseContent; //Content is assumed JSON
78✔
110
        }
82✔
111

112
        internal async Task<T> PutWithJsonPayload<T>(string suffix, CancellationToken cancellationToken, string payload, params QueryParameter[] parameters)
113
        {
114
            string json = await PutWithJsonPayload(suffix, cancellationToken, payload, 0, parameters);
15✔
115
            var @object = JsonSerializer.Deserialize<T>(json);
15✔
116
            return @object;
15✔
117
        }
15✔
118

119
        internal async Task<string> PutWithJsonPayload(string suffix, CancellationToken cancellationToken, string payload, int retryCount, params QueryParameter[] parameters)
120
        {
121
            var uri = BuildUri(suffix, parameters);
16✔
122
            var response = await _httpClient.PutAsync(uri, new StringContent(payload, Encoding.UTF8, "application/json"), cancellationToken);
16✔
123
            var responseContent = await response.Content.ReadAsStringAsync();
16✔
124
            if (response.StatusCode != HttpStatusCode.OK)
16!
125
            {
126
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => PutWithJsonPayload(suffix, cancellationToken, payload, retry, parameters), retryCount, cancellationToken);
×
127
            }
128
            return responseContent; //Content is assumed JSON
16✔
129
        }
16✔
130

131
        private string FormatExceptionUrlAccordingToClientOptions(string fullUrl)
132
        {
133
            switch (_client.Options.ApiCallExceptionOption)
7!
134
            {
135
                case ApiCallExceptionOption.IncludeUrlAndCredentials:
136
                    return fullUrl;
1✔
137
                case ApiCallExceptionOption.IncludeUrlButMaskCredentials:
138
                    // ReSharper disable StringLiteralTypo
139
                    return fullUrl.Replace($"?key={_apiKey}&token={_token}", "?key=XXXXX&token=XXXXXXXXXX");
5✔
140
                case ApiCallExceptionOption.DoNotIncludeTheUrl:
141
                    return string.Empty.PadLeft(5, 'X');
1✔
142
                default:
143
                    throw new ArgumentOutOfRangeException();
×
144
            }
145
        }
146

147
        internal static StringBuilder GetParametersAsString(QueryParameter[] parameters)
148
        {
149
            StringBuilder parameterString = new StringBuilder();
768✔
150
            foreach (var parameter in parameters)
6,548✔
151
            {
152
                parameterString.Append($"&{parameter.Name}={parameter.GetValueAsApiFormattedString()}");
2,506✔
153
            }
154

155
            return parameterString;
768✔
156
        }
157

158
        private Uri BuildUri(string suffix, params QueryParameter[] parameters)
159
        {
160
            string separator = suffix.Contains("?") ? "&" : "?";
768!
161
            return new Uri($"{BaseUrl}{suffix}{separator}key={_apiKey}&token={_token}" + GetParametersAsString(parameters));
768!
162
        }
163

164
        internal async Task<string> Delete(string suffix, CancellationToken cancellationToken, int retryCount)
165
        {
166
            var uri = BuildUri(suffix);
59✔
167
            var response = await _httpClient.DeleteAsync(uri, cancellationToken);
59✔
168
            var responseContent = await response.Content.ReadAsStringAsync();
59✔
169
            if (response.StatusCode != HttpStatusCode.OK)
59✔
170
            {
171
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => Delete(suffix, cancellationToken, retry), retryCount, cancellationToken);
23✔
172
            }
173
            return null;
47✔
174
        }
58✔
175

176
        private async Task<string> PreformRetryIfNeededOrThrow(Uri uri, string responseContent, Func<int,Task<string>> toRetry, int retryCount, CancellationToken cancellationToken)
177
        {
178
            if (responseContent.Contains("API_TOKEN_LIMIT_EXCEEDED") && retryCount <= _client.Options.MaxRetryCountForTokenLimitExceeded)
65✔
179
            {
180
                await Task.Delay(TimeSpan.FromSeconds(_client.Options.DelayInSecondsToWaitInTokenLimitExceededRetry), cancellationToken);
58✔
181
                retryCount++;
58✔
182
                return await toRetry(retryCount);
58✔
183
            }
184
            throw new TrelloApiException(responseContent, FormatExceptionUrlAccordingToClientOptions(uri.AbsoluteUri)); //Content is assumed Error Message       
7✔
185
        }
58✔
186
    }
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc