diff --git a/.editorconfig b/.editorconfig index d344159..68f1dcb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -516,4 +516,11 @@ csharp_wrap_lines = false # オブジェクト初期化子とコレクション初期化子のラップスタイルを指定する csharp_wrap_object_and_collection_initializer_style = wrap_if_long # プロパティパターンのラップスタイルを指定する -csharp_wrap_property_pattern = chop_if_long \ No newline at end of file +csharp_wrap_property_pattern = chop_if_long +# フォルダ構造とnamespaceが違っても警告しない +dotnet_style_namespace_match_folder = false +# this を必須にする +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_property = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_event = true:warning \ No newline at end of file diff --git a/SharpChatwork/src/Attribute/EnumAliasAttribute.cs b/SharpChatwork/src/Attribute/EnumAliasAttribute.cs index ff7a83e..5924ff2 100644 --- a/SharpChatwork/src/Attribute/EnumAliasAttribute.cs +++ b/SharpChatwork/src/Attribute/EnumAliasAttribute.cs @@ -4,13 +4,9 @@ namespace SharpChatwork; [AttributeUsage(AttributeTargets.Field)] -internal sealed class EnumAliasAttribute : Attribute +internal sealed class EnumAliasAttribute(string aliasName) : Attribute { - public EnumAliasAttribute(string aliasName) - { - this.AliasName = aliasName; - } - public string AliasName { get; set; } + public string aliasName { get; set; } = aliasName; } internal static class EnumAliasExtension @@ -27,6 +23,6 @@ public static string ToAliasOrDefault(this Enum value) if(i == null) return Enum.GetName(value.GetType(), value); // use alias - return i.AliasName; + return i.aliasName; } } diff --git a/SharpChatwork/src/Client/AccessToken/AccessTokenClient.cs b/SharpChatwork/src/Client/AccessToken/AccessTokenClient.cs index f6526ac..cc671cb 100644 --- a/SharpChatwork/src/Client/AccessToken/AccessTokenClient.cs +++ b/SharpChatwork/src/Client/AccessToken/AccessTokenClient.cs @@ -8,10 +8,10 @@ namespace SharpChatwork.AccessToken; public class AccessTokenClient(string accessToken, HttpMessageInvoker messageInvoker = null) : ChatworkClient { - private readonly HttpMessageInvoker _messageInvoker = messageInvoker ?? new HttpClient(); + private readonly HttpMessageInvoker MessageInvoker = messageInvoker ?? new HttpClient(); public override string clientName => nameof(AccessTokenClient); - private string accessToken { get; } = accessToken; + private string _accessToken { get; } = accessToken; private HttpRequestMessage GenerateRequestMessage(Uri uri, HttpMethod method) { @@ -20,7 +20,7 @@ private HttpRequestMessage GenerateRequestMessage(Uri uri, HttpMethod method) Method = method, RequestUri = uri, }; - request.Headers.Add("X-ChatWorkToken", this.accessToken); + request.Headers.Add("X-ChatWorkToken", this._accessToken); return request; } @@ -28,7 +28,7 @@ public override async ValueTask QueryAsync(Uri uri, HttpMethod { var requestMessage = this.GenerateRequestMessage(uri, method); requestMessage.Content = content; - var client = this._messageInvoker; + var client = this.MessageInvoker; var result = await client.SendAsync(requestMessage, cancellation); var code = (int)result.StatusCode; return new ResponseWrapper diff --git a/SharpChatwork/src/Client/Exceptions/ChatworkClientException.cs b/SharpChatwork/src/Client/Exceptions/ChatworkClientException.cs index 11513de..144fbec 100644 --- a/SharpChatwork/src/Client/Exceptions/ChatworkClientException.cs +++ b/SharpChatwork/src/Client/Exceptions/ChatworkClientException.cs @@ -4,5 +4,10 @@ namespace SharpChatwork.Client.Exceptions; public class ChatworkClientException(ResponseWrapper response) : Exception { - public readonly ResponseWrapper response = response; + public readonly ResponseWrapper Response = response; + + public override string ToString() + { + return base.ToString() + $" --> ChatworkClientException: {this.Response.statusCode} {this.Response.content}"; + } } diff --git a/SharpChatwork/src/Client/IChatworkClient.cs b/SharpChatwork/src/Client/IChatworkClient.cs index 38f2c4f..c959809 100644 --- a/SharpChatwork/src/Client/IChatworkClient.cs +++ b/SharpChatwork/src/Client/IChatworkClient.cs @@ -11,7 +11,9 @@ namespace SharpChatwork; public interface IChatworkClient { +#pragma warning disable CA1716 IMeQuery me { get; } +#pragma warning restore CA1716 IRoomQuery room { get; } IContactQuery contact { get; } IIncomingRequestQuery incomingRequest { get; } diff --git a/SharpChatwork/src/Client/OAuth2/OAuth2Client.cs b/SharpChatwork/src/Client/OAuth2/OAuth2Client.cs index 774aa0f..8d0d353 100644 --- a/SharpChatwork/src/Client/OAuth2/OAuth2Client.cs +++ b/SharpChatwork/src/Client/OAuth2/OAuth2Client.cs @@ -17,17 +17,17 @@ public class OAuth2Client(string clientKey, string secretKey, HttpMessageInvoker { public override string clientName => nameof(OAuth2Client); - private readonly HttpMessageInvoker _messageInvoker = invoker ?? new HttpClient(); - private string clientKey { get; } = clientKey; - private string secretKey { get; } = secretKey; - private string oauth2Code { get; set; } = string.Empty; - private string accessToken { get; set; } = string.Empty; - private string refleshToken { get; set; } = string.Empty; - private long tokenExpired { get; set; } = 0; + private readonly HttpMessageInvoker MessageInvoker = invoker ?? new HttpClient(); + private string _clientKey { get; } = clientKey; + private string _secretKey { get; } = secretKey; + private string _oauth2Code { get; set; } = string.Empty; + private string _accessToken { get; set; } = string.Empty; + private string _refreshToken { get; set; } = string.Empty; + private long _tokenExpired { get; set; } = 0; - private string scope { get; set; } = string.Empty; - private string redirectUri { get; set; } = string.Empty; - private DateTime tokenQueryTime { get; set; } = DateTime.Now; + private string _scope { get; set; } = string.Empty; + private string _redirectUri { get; set; } = string.Empty; + private DateTime _tokenQueryTime { get; set; } = DateTime.Now; private HttpRequestMessage GenerateRequestMessage(Uri uri, HttpMethod method) { @@ -36,7 +36,7 @@ private HttpRequestMessage GenerateRequestMessage(Uri uri, HttpMethod method) Method = method, RequestUri = uri, }; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this._accessToken); return request; } @@ -44,7 +44,7 @@ public override async ValueTask QueryAsync(Uri uri, HttpMethod { var requestMessage = this.GenerateRequestMessage(uri, method); requestMessage.Content = content; - var client = this._messageInvoker; + var client = this.MessageInvoker; var result = await client.SendAsync(requestMessage, cancellation); var code = (int)result.StatusCode; @@ -58,21 +58,21 @@ public override async ValueTask QueryAsync(Uri uri, HttpMethod public OAuth2ConcentQueryResult Authorization(OAuth2ConcentQuery query, string codeVerifer = "") { - query.client_id = this.clientKey; - this.scope = query.scope; - this.redirectUri = query.redirect_uri; + query.client_id = this._clientKey; + this._scope = query.scope; + this._redirectUri = query.redirect_uri; // TODO Only windows - var concentUrlArg = EndPoints.Oauth2.OriginalString + $"{UrlArgEncoder.ToURLArg(query)}"; + var contentUrlArg = EndPoints.Oauth2.OriginalString + $"{UrlArgEncoder.ToURLArg(query)}"; Console.WriteLine("Please input code of redirect url code="); Process.Start( - new ProcessStartInfo("cmd", $"/c start {concentUrlArg}") + new ProcessStartInfo("cmd", $"/c start {contentUrlArg}") { CreateNoWindow = true, } ); - this.oauth2Code = Console.ReadLine(); + this._oauth2Code = Console.ReadLine(); - if(string.IsNullOrEmpty(this.oauth2Code)) + if(string.IsNullOrEmpty(this._oauth2Code)) { return new OAuth2ConcentQueryResult { @@ -80,19 +80,19 @@ public OAuth2ConcentQueryResult Authorization(OAuth2ConcentQuery query, string c //error_description = "inputed oauth_code is null or empty", }; } - query.client_id = this.clientKey; + query.client_id = this._clientKey; return new OAuth2ConcentQueryResult { - code = this.oauth2Code, + code = this._oauth2Code, }; } - public async Task UpdateToken(OAuth2TokenQuery.GrantType grantType = OAuth2TokenQuery.GrantType.RefreshToken, string codeVerifer = "", CancellationToken cancellation = default) + public async Task UpdateTokenAsync(OAuth2TokenQuery.GrantType grantType = OAuth2TokenQuery.GrantType.RefreshToken, string codeVerifer = "", CancellationToken cancellation = default) { var tokenQuery = new OAuth2TokenQuery(grantType) { - scope = this.scope, - redirect_uri = this.redirectUri, + scope = this._scope, + redirect_uri = this._redirectUri, }; var request = new HttpRequestMessage { @@ -101,26 +101,26 @@ public async Task UpdateToken(OAuth2TokenQuery.GrantType }; if(grantType == OAuth2TokenQuery.GrantType.AuthroizationCode) - tokenQuery.code = this.oauth2Code; + tokenQuery.code = this._oauth2Code; else if(grantType == OAuth2TokenQuery.GrantType.RefreshToken) - tokenQuery.refresh_token = this.refleshToken; + tokenQuery.refresh_token = this._refreshToken; request.Headers.Authorization = new AuthenticationHeaderValue( "Basic", - Convert.ToBase64String(Encoding.ASCII.GetBytes($"{this.clientKey}:{this.secretKey}")) + Convert.ToBase64String(Encoding.ASCII.GetBytes($"{this._clientKey}:{this._secretKey}")) ); request.Content = new FormUrlEncodedContent(UrlArgEncoder.ToDictionary(tokenQuery)); - var client = this._messageInvoker; + var client = this.MessageInvoker; var response = await client.SendAsync(request, cancellation); var stream = await response.Content.ReadAsStreamAsync(); using var reader = new StreamReader(stream); - var result = JsonSerializer.Deserialize(reader.ReadToEnd()); - this.tokenExpired = result.expires_in; - this.tokenQueryTime = DateTime.Now; - this.refleshToken = result.refresh_token; - this.accessToken = result.access_token; + var result = JsonSerializer.Deserialize(await reader.ReadToEndAsync()); + this._tokenExpired = result.expires_in; + this._tokenQueryTime = DateTime.Now; + this._refreshToken = result.refresh_token; + this._accessToken = result.access_token; return result; } } diff --git a/SharpChatwork/src/Client/OAuth2/OAuth2ConcentQuery.cs b/SharpChatwork/src/Client/OAuth2/OAuth2ConcentQuery.cs index b2c4c6b..b778aee 100644 --- a/SharpChatwork/src/Client/OAuth2/OAuth2ConcentQuery.cs +++ b/SharpChatwork/src/Client/OAuth2/OAuth2ConcentQuery.cs @@ -4,7 +4,9 @@ namespace SharpChatwork.OAuth2; public class OAuth2ConcentQuery { +#pragma warning disable CA1822 public string response_type => "code"; +#pragma warning restore CA1822 public string client_id { get; set; } = string.Empty; public string redirect_uri { get; set; } = string.Empty; public string scope { get; set; } = string.Empty; diff --git a/SharpChatwork/src/Client/OAuth2/OAuth2TokenQuery.cs b/SharpChatwork/src/Client/OAuth2/OAuth2TokenQuery.cs index 9fa3e9d..a175fcd 100644 --- a/SharpChatwork/src/Client/OAuth2/OAuth2TokenQuery.cs +++ b/SharpChatwork/src/Client/OAuth2/OAuth2TokenQuery.cs @@ -2,7 +2,7 @@ namespace SharpChatwork.OAuth2; -public class OAuth2TokenQuery +public class OAuth2TokenQuery(OAuth2TokenQuery.GrantType type) { public enum GrantType { @@ -12,7 +12,7 @@ public enum GrantType RefreshToken, } - public string grant_type { get; set; } = string.Empty; + public string grant_type { get; set; } = type.ToAliasOrDefault(); public string code { get; set; } = string.Empty; public string redirect_uri { get; set; } = string.Empty; public string code_verifier { get; set; } = string.Empty; @@ -25,9 +25,4 @@ public ScopeType scopeType get => this._scopeType; set { this._scopeType = value; this.scope = this._scopeType.ToUrlArg(); } } - - public OAuth2TokenQuery(GrantType type) - { - this.grant_type = type.ToAliasOrDefault(); - } } diff --git a/SharpChatwork/src/Client/OAuth2/Scope.cs b/SharpChatwork/src/Client/OAuth2/Scope.cs index 4acd14f..cdfc963 100644 --- a/SharpChatwork/src/Client/OAuth2/Scope.cs +++ b/SharpChatwork/src/Client/OAuth2/Scope.cs @@ -6,8 +6,9 @@ namespace SharpChatwork.OAuth2; /// -/// API access scopes -/// implement from here http://developer.chatwork.com/ja/oauth.html#secAppendix +/// API access scopes +/// +/// implement from here http://developer.chatwork.com/ja/oauth.html#secAppendix /// public enum ScopeType : long { @@ -17,7 +18,7 @@ public enum ScopeType : long [Description("自分のアカウントに紐づく情報の取得")] [EnumAlias("users.all:read")] - UsersAllR = UsersProfileMeR | UsersTasksMeR | UsersStatusMeR, + UsersAllR = ScopeType.UsersProfileMeR | ScopeType.UsersTasksMeR | ScopeType.UsersStatusMeR, [Description("自分のプロフィール情報の取得")] [EnumAlias("users.profile.me:read")] @@ -33,7 +34,7 @@ public enum ScopeType : long [Description("チャットルームに紐づくメッセージ・タスク・ファイル・概要・メンバー情報の操作/取得")] [EnumAlias("rooms.all:read_write")] - RoomsAllRW = RoomsAllR | RoomsAllW, + RoomsAllRW = ScopeType.RoomsAllR | ScopeType.RoomsAllW, [Description("チャットルームに紐づくメッセージ・タスク・ファイル・概要・メンバー情報の取得")] [EnumAlias("rooms.all:read")] @@ -89,7 +90,7 @@ public enum ScopeType : long [Description("自分のコンタクト、及びコンタクト承認依頼情報の取得/操作")] [EnumAlias("contacts.all:read_write")] - ContactsAllRW = ContactsAllR | ContactsAllW, + ContactsAllRW = ScopeType.ContactsAllR | ScopeType.ContactsAllW, [Description("自分のコンタクト、及びコンタクト承認依頼情報の取得")] [EnumAlias("contacts.all:read")] @@ -106,14 +107,19 @@ public static string ToUrlArg(this ScopeType type) { // extract name value pair var enumValues = Enum.GetValues(typeof(ScopeType)).OfType(); - var enumNames = enumValues.Select(m => FindAttribute(m)); + var enumNames = enumValues.Select(ScopeTypeExtension.FindAttribute); var input = (long)type; var enumNameValues = enumNames - .Zip(enumValues, (m, n) => new { m.AliasName, Value = n }) + .Zip( + enumValues, (m, n) => new + { + AliasName = m.aliasName, + Value = n, + } + ) .Where(m => ((long)m.Value & input) != 0) .Reverse(); - - List> resultScopes = new List>(); + var resultScopes = new List>(); // escape _all child foreach(var item in enumNameValues) @@ -134,12 +140,8 @@ private static AttributeT FindAttribute(ScopeType type) where Attrib var attributes = fieldInfo .GetCustomAttributes(typeof(AttributeT), false) .Cast(); - - if(attributes == null) - return null; if(!attributes.Any()) return null; - return attributes.First(); } } diff --git a/SharpChatwork/src/Client/Query/RoomFileQuery.cs b/SharpChatwork/src/Client/Query/RoomFileQuery.cs index d63a483..f74e5bc 100644 --- a/SharpChatwork/src/Client/Query/RoomFileQuery.cs +++ b/SharpChatwork/src/Client/Query/RoomFileQuery.cs @@ -10,12 +10,8 @@ namespace SharpChatwork.Query; -internal sealed class RoomFileQuery : ClientQuery, IRoomFileQuery +internal sealed class RoomFileQuery(IChatworkClient client) : ClientQuery(client), IRoomFileQuery { - public RoomFileQuery(IChatworkClient client) : base(client) - { - } - public async ValueTask> GetAllAsync(long roomId, long accountId, CancellationToken token = default) { var uri = $"{EndPoints.RoomFiles(roomId)}?account_id={accountId}"; diff --git a/SharpChatwork/src/Client/Query/RoomInviteQuery.cs b/SharpChatwork/src/Client/Query/RoomInviteQuery.cs index d4ee7fb..7e00f5f 100644 --- a/SharpChatwork/src/Client/Query/RoomInviteQuery.cs +++ b/SharpChatwork/src/Client/Query/RoomInviteQuery.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -14,7 +15,7 @@ public async ValueTask CreateAsync(long roomId, string uniqueName, s { {"code", uniqueName}, {"description", description}, - {"need_acceptance", UrlArgEncoder.BoolToInt(requireAcceptance).ToString()}, + {"need_acceptance", UrlArgEncoder.BoolToInt(requireAcceptance).ToString(CultureInfo.InvariantCulture)}, }; return await this.chatworkClient.QueryAsync(EndPoints.RoomTasks(roomId), HttpMethod.Post, data, token); } @@ -35,7 +36,7 @@ public async ValueTask UpdateAsync(long roomId, string uniqueName, s { {"code", uniqueName}, {"description", description}, - {"need_acceptance", UrlArgEncoder.BoolToInt(requireAcceptance).ToString()}, + {"need_acceptance", UrlArgEncoder.BoolToInt(requireAcceptance).ToString(CultureInfo.InvariantCulture)}, }; return await this.chatworkClient.QueryAsync(EndPoints.RoomTasks(roomId), HttpMethod.Put, data, token); } diff --git a/SharpChatwork/src/Client/Query/RoomMessageQuery.cs b/SharpChatwork/src/Client/Query/RoomMessageQuery.cs index 58f6097..f5e7985 100644 --- a/SharpChatwork/src/Client/Query/RoomMessageQuery.cs +++ b/SharpChatwork/src/Client/Query/RoomMessageQuery.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -38,7 +39,7 @@ public async ValueTask SendAsync(long roomId, string message, bool is var data = new Dictionary { {"body", message}, - {"self_unread", UrlArgEncoder.BoolToInt(isSelfUnread).ToString()}, + {"self_unread", UrlArgEncoder.BoolToInt(isSelfUnread).ToString(CultureInfo.InvariantCulture)}, }; return await this.chatworkClient.QueryAsync(EndPoints.RoomMessages(roomId), HttpMethod.Post, data, token); } diff --git a/SharpChatwork/src/Client/Query/RoomTaskQuery.cs b/SharpChatwork/src/Client/Query/RoomTaskQuery.cs index 3dbaa19..19fe54a 100644 --- a/SharpChatwork/src/Client/Query/RoomTaskQuery.cs +++ b/SharpChatwork/src/Client/Query/RoomTaskQuery.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -34,8 +35,8 @@ public async ValueTask> GetAllAsync(long roomId, long acco doneString = "open"; var data = new Dictionary { - {"account_id", accountId.ToString()}, - {"assigned_by_account_id", autherId.ToString()}, + {"account_id", accountId.ToString(CultureInfo.InvariantCulture)}, + {"assigned_by_account_id", autherId.ToString(CultureInfo.InvariantCulture)}, {"status", doneString}, }; return await this.chatworkClient.QueryAsync>(EndPoints.RoomTasks(roomId), HttpMethod.Get, data, token); diff --git a/SharpChatwork/src/Client/QueryResult/Ids/FileId.cs b/SharpChatwork/src/Client/QueryResult/Ids/FileId.cs index 95e83db..585ba4e 100644 --- a/SharpChatwork/src/Client/QueryResult/Ids/FileId.cs +++ b/SharpChatwork/src/Client/QueryResult/Ids/FileId.cs @@ -4,7 +4,7 @@ namespace SharpChatwork.Query.Types; public class FileId : ElementId { - public string File_id + public string file_id { get => this.id; set => this.id = value; diff --git a/SharpChatwork/src/Client/QueryResult/RoomMember.cs b/SharpChatwork/src/Client/QueryResult/RoomMember.cs index baf83f6..9c12f6d 100644 --- a/SharpChatwork/src/Client/QueryResult/RoomMember.cs +++ b/SharpChatwork/src/Client/QueryResult/RoomMember.cs @@ -6,7 +6,7 @@ namespace SharpChatwork.Query.Types; public class RoomMember { - public List admin { get; set; } = new List(); - public List member { get; set; } = new List(); - public List @readonly { get; set; } = new List(); + public List admin { get; set; } = []; + public List member { get; set; } = []; + public List @readonly { get; set; } = []; }