From 8507c3b3802b0990c681a7c17c4e4d7ef0fa305d Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 1 Dec 2022 19:19:47 +0800 Subject: Restructure crupest-api. --- docker/crupest-api/CrupestApi/.dockerignore | 4 +- .../CrupestApi/Config/TodosConfiguration.cs | 15 --- .../CrupestApi.Database/CrupestApi.Database.csproj | 9 ++ .../DatabaseMigrationManager.cs | 0 .../CrupestApi.Database/DatabaseService.cs | 0 .../CrupestApi.Files/CrupestApi.Files.csproj | 9 ++ .../CrupestApi/CrupestApi.Files/FilesService.cs | 6 + .../CrupestApi.Todos/CrupestApi.Todos.csproj | 9 ++ .../CrupestApi.Todos/TodosConfiguration.cs | 14 ++ .../CrupestApi/CrupestApi.Todos/TodosService.cs | 144 ++++++++++++++++++++ .../TodosServiceCollectionExtensions.cs | 22 ++++ .../TodosWebApplicationExtensions.cs | 41 ++++++ docker/crupest-api/CrupestApi/CrupestApi.csproj | 8 -- docker/crupest-api/CrupestApi/CrupestApi.sln | 28 ++++ .../CrupestApi/CrupestApi/CrupestApi.csproj | 14 ++ .../crupest-api/CrupestApi/CrupestApi/Program.cs | 17 +++ .../CrupestApi/Properties/launchSettings.json | 15 +++ .../CrupestApi/CrupestApi/appsettings.json | 8 ++ docker/crupest-api/CrupestApi/Program.cs | 59 --------- .../CrupestApi/Properties/launchSettings.json | 15 --- .../crupest-api/CrupestApi/Services/FileService.cs | 10 -- .../crupest-api/CrupestApi/Services/TodoService.cs | 146 --------------------- docker/crupest-api/CrupestApi/appsettings.json | 8 -- 23 files changed, 338 insertions(+), 263 deletions(-) delete mode 100644 docker/crupest-api/CrupestApi/Config/TodosConfiguration.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseMigrationManager.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseService.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Files/FilesService.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosConfiguration.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosService.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosServiceCollectionExtensions.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs delete mode 100644 docker/crupest-api/CrupestApi/CrupestApi.csproj create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.sln create mode 100644 docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj create mode 100644 docker/crupest-api/CrupestApi/CrupestApi/Program.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json create mode 100644 docker/crupest-api/CrupestApi/CrupestApi/appsettings.json delete mode 100644 docker/crupest-api/CrupestApi/Program.cs delete mode 100644 docker/crupest-api/CrupestApi/Properties/launchSettings.json delete mode 100644 docker/crupest-api/CrupestApi/Services/FileService.cs delete mode 100644 docker/crupest-api/CrupestApi/Services/TodoService.cs delete mode 100644 docker/crupest-api/CrupestApi/appsettings.json (limited to 'docker/crupest-api') diff --git a/docker/crupest-api/CrupestApi/.dockerignore b/docker/crupest-api/CrupestApi/.dockerignore index 7de5508..f1c182d 100644 --- a/docker/crupest-api/CrupestApi/.dockerignore +++ b/docker/crupest-api/CrupestApi/.dockerignore @@ -1,2 +1,2 @@ -obj -bin +*/obj +*/bin diff --git a/docker/crupest-api/CrupestApi/Config/TodosConfiguration.cs b/docker/crupest-api/CrupestApi/Config/TodosConfiguration.cs deleted file mode 100644 index 68f893a..0000000 --- a/docker/crupest-api/CrupestApi/Config/TodosConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace CrupestApi.Config -{ - public class TodoConfiguration - { - [Required] - public string Username { get; set; } = default!; - [Required] - public int ProjectNumber { get; set; } = default!; - [Required] - public string Token { get; set; } = default!; - public int? Count { get; set; } - } -} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj new file mode 100644 index 0000000..72a1294 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseMigrationManager.cs b/docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseMigrationManager.cs new file mode 100644 index 0000000..e69de29 diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseService.cs new file mode 100644 index 0000000..e69de29 diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj new file mode 100644 index 0000000..72a1294 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Files/FilesService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Files/FilesService.cs new file mode 100644 index 0000000..c851a92 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Files/FilesService.cs @@ -0,0 +1,6 @@ +namespace CrupestApi.Files; + +public class FilesService +{ + +} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj new file mode 100644 index 0000000..72a1294 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosConfiguration.cs b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosConfiguration.cs new file mode 100644 index 0000000..e8160d2 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosConfiguration.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace CrupestApi.Todos; + +public class TodosConfiguration +{ + [Required] + public string Username { get; set; } = default!; + [Required] + public int ProjectNumber { get; set; } = default!; + [Required] + public string Token { get; set; } = default!; + public int Count { get; set; } +} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosService.cs new file mode 100644 index 0000000..f5ccc09 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosService.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Mime; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace CrupestApi.Todos; + +public class TodosItem +{ + public string Status { get; set; } = default!; + public string Title { get; set; } = default!; + public bool Closed { get; set; } + public string Color { get; set; } = default!; +} + +public class TodosService +{ + private readonly IOptionsSnapshot _options; + private readonly ILogger _logger; + + public TodosService(IOptionsSnapshot options, ILogger logger) + { + _options = options; + _logger = logger; + } + + private static string CreateGraphQLQuery(TodosConfiguration todoConfiguration) + { + return $$""" +{ + user(login: "{{todoConfiguration.Username}}") { + projectV2(number: {{todoConfiguration.ProjectNumber}}) { + items(last: {{todoConfiguration.Count}}) { + nodes { + __typename + content { + __typename + ... on Issue { + title + closed + } + ... on PullRequest { + title + closed + } + ... on DraftIssue { + title + } + } + } + } + } + } +} +"""; + } + + + public async Task> GetTodosAsync() + { + var todoOptions = _options.Value; + if (todoOptions is null) + { + throw new Exception("Fail to get todos configuration."); + } + + _logger.LogInformation("Username: {}; ProjectNumber: {}; Count: {}", todoOptions.Username, todoOptions.ProjectNumber, todoOptions.Count); + _logger.LogInformation("Getting todos from GitHub GraphQL API..."); + + using var httpClient = new HttpClient(); + + using var requestContent = new StringContent(JsonSerializer.Serialize(new + { + query = CreateGraphQLQuery(todoOptions) + })); + requestContent.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Json, Encoding.UTF8.WebName); + + using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.github.com/graphql"); + request.Content = requestContent; + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", todoOptions.Token); + request.Headers.TryAddWithoutValidation("User-Agent", todoOptions.Username); + + using var response = await httpClient.SendAsync(request); + var responseBody = await response.Content.ReadAsStringAsync(); + + _logger.LogInformation("GitHub server returned status code: {}", response.StatusCode); + _logger.LogInformation("GitHub server returned body: {}", responseBody); + + if (response.IsSuccessStatusCode) + { + using var responseJson = JsonSerializer.Deserialize(responseBody); + if (responseJson is null) + { + throw new Exception("Fail to deserialize response body."); + } + + var nodes = responseJson.RootElement.GetProperty("data").GetProperty("user").GetProperty("projectV2").GetProperty("items").GetProperty("nodes").EnumerateArray(); + + var result = new List(); + + foreach (var node in nodes) + { + var content = node.GetProperty("content"); + var title = content.GetProperty("title").GetString(); + if (title is null) + { + throw new Exception("Fail to get title."); + } + JsonElement closedElement; + bool closed; + if (content.TryGetProperty("closed", out closedElement)) + { + closed = closedElement.GetBoolean(); + } + else + { + closed = false; + } + + result.Add(new TodosItem + { + Title = title, + Status = closed ? "Done" : "Todo", + Closed = closed, + Color = closed ? "green" : "blue" + }); + } + + return result; + } + else + { + const string message = "Fail to get todos from GitHub."; + _logger.LogError(message); + throw new Exception(message); + } + } +} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosServiceCollectionExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosServiceCollectionExtensions.cs new file mode 100644 index 0000000..cdf174d --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosServiceCollectionExtensions.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace CrupestApi.Todos; + +public static class TodosServiceCollectionExtensions +{ + public static IServiceCollection AddTodos(this IServiceCollection services) + { + services.AddOptions().BindConfiguration("Todos"); + services.PostConfigure(config => + { + if (config.Count == 0) + { + config.Count = 20; + } + }); + services.TryAddScoped(); + return services; + } +} + diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs new file mode 100644 index 0000000..575dc4f --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.Text.Json; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace CrupestApi.Todos; + +public static class TodosWebApplicationExtensions +{ + public static WebApplication MapTodos(this WebApplication app, string path) + { + if (app is null) + { + throw new ArgumentNullException(nameof(app)); + } + + app.MapGet(path, async ([FromServices] TodosService todosService) => + { + var jsonOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + try + { + var todos = await todosService.GetTodosAsync(); + return Results.Json(todos, jsonOptions, statusCode: 200); + } + catch (Exception e) + { + return Results.Json(new + { + e.Message + }, jsonOptions, statusCode: StatusCodes.Status503ServiceUnavailable); + } + }); + + return app; + } +} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/CrupestApi.csproj b/docker/crupest-api/CrupestApi/CrupestApi.csproj deleted file mode 100644 index 4348979..0000000 --- a/docker/crupest-api/CrupestApi/CrupestApi.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - net7.0 - enable - - - diff --git a/docker/crupest-api/CrupestApi/CrupestApi.sln b/docker/crupest-api/CrupestApi/CrupestApi.sln new file mode 100644 index 0000000..f22c307 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrupestApi", "CrupestApi\CrupestApi.csproj", "{E30916BB-08F9-45F0-BC1A-69B66AE79913}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrupestApi.Todos", "CrupestApi.Todos\CrupestApi.Todos.csproj", "{BF9F5F71-AE65-4896-8E6F-FE0D4AD0E7D1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E30916BB-08F9-45F0-BC1A-69B66AE79913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E30916BB-08F9-45F0-BC1A-69B66AE79913}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E30916BB-08F9-45F0-BC1A-69B66AE79913}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E30916BB-08F9-45F0-BC1A-69B66AE79913}.Release|Any CPU.Build.0 = Release|Any CPU + {BF9F5F71-AE65-4896-8E6F-FE0D4AD0E7D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF9F5F71-AE65-4896-8E6F-FE0D4AD0E7D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF9F5F71-AE65-4896-8E6F-FE0D4AD0E7D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF9F5F71-AE65-4896-8E6F-FE0D4AD0E7D1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj b/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj new file mode 100644 index 0000000..c15ec91 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj @@ -0,0 +1,14 @@ + + + + + + + + + net7.0 + enable + enable + + + diff --git a/docker/crupest-api/CrupestApi/CrupestApi/Program.cs b/docker/crupest-api/CrupestApi/CrupestApi/Program.cs new file mode 100644 index 0000000..e18252f --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi/Program.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using CrupestApi.Todos; + +var builder = WebApplication.CreateBuilder(args); + +string configFilePath = Environment.GetEnvironmentVariable("CRUPEST_API_CONFIG_FILE") ?? "/crupest-api-config.json"; +builder.Configuration.AddJsonFile(configFilePath, optional: false, reloadOnChange: true); + +builder.Services.AddTodos(); + +var app = builder.Build(); + +app.MapTodos("/api/todos"); + +app.Run(); diff --git a/docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json b/docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json new file mode 100644 index 0000000..a4a5cbf --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "dev": { + "commandName": "Project", + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5188", + "workingDirectory": ".", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "CRUPEST_API_CONFIG_FILE": "dev-config.json" + } + } + } +} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/CrupestApi/appsettings.json b/docker/crupest-api/CrupestApi/CrupestApi/appsettings.json new file mode 100644 index 0000000..53753bd --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/Program.cs b/docker/crupest-api/CrupestApi/Program.cs deleted file mode 100644 index 9f7e7df..0000000 --- a/docker/crupest-api/CrupestApi/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Text.Json; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.DependencyInjection; -using CrupestApi.Config; -using CrupestApi.Services; - -namespace CrupestApi -{ - internal class Program - { - private static void Main(string[] args) - { - - var builder = WebApplication.CreateBuilder(args); - - string configFilePath = Environment.GetEnvironmentVariable("CRUPEST_API_CONFIG_FILE") ?? "/crupest-api-config.json"; - builder.Configuration.AddJsonFile(configFilePath, optional: false, reloadOnChange: true); - - builder.Services.AddOptions(); - builder.Services.Configure(builder.Configuration.GetSection("Todos")); - builder.Services.PostConfigure(config => - { - if (config.Count is null) - { - config.Count = 20; - } - }); - builder.Services.TryAddScoped(); - - var app = builder.Build(); - - app.MapGet("/api/todos", async ([FromServices] TodoService todoService) => - { - try - { - var todos = await todoService.GetTodosAsync(); - return Results.Json(todos, new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }, statusCode: 200); - } - catch (Exception e) - { - return Results.Json(new - { - e.Message - }, statusCode: StatusCodes.Status503ServiceUnavailable); - } - }); - - app.Run(); - } - } -} diff --git a/docker/crupest-api/CrupestApi/Properties/launchSettings.json b/docker/crupest-api/CrupestApi/Properties/launchSettings.json deleted file mode 100644 index a4a5cbf..0000000 --- a/docker/crupest-api/CrupestApi/Properties/launchSettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "dev": { - "commandName": "Project", - "dotnetRunMessages": true, - "applicationUrl": "http://localhost:5188", - "workingDirectory": ".", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "CRUPEST_API_CONFIG_FILE": "dev-config.json" - } - } - } -} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/Services/FileService.cs b/docker/crupest-api/CrupestApi/Services/FileService.cs deleted file mode 100644 index d862702..0000000 --- a/docker/crupest-api/CrupestApi/Services/FileService.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace CrupestApi.Services -{ - public class FileService - { - public FileService() - { - - } - } -} diff --git a/docker/crupest-api/CrupestApi/Services/TodoService.cs b/docker/crupest-api/CrupestApi/Services/TodoService.cs deleted file mode 100644 index eb4fef6..0000000 --- a/docker/crupest-api/CrupestApi/Services/TodoService.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Mime; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; -using CrupestApi.Config; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace CrupestApi.Services -{ - public class TodoItem - { - public string Status { get; set; } = default!; - public string Title { get; set; } = default!; - public bool Closed { get; set; } - public string color { get; set; } = default!; - } - - public class TodoService - { - private readonly IOptionsSnapshot _options; - private readonly ILogger _logger; - - public TodoService(IOptionsSnapshot options, ILogger logger) - { - _options = options; - _logger = logger; - } - - private static string CreateGraphQLQuery(TodoConfiguration todoConfiguration) - { - return $$""" -{ - user(login: "{{todoConfiguration.Username}}") { - projectV2(number: {{todoConfiguration.ProjectNumber}}) { - items(last: {{todoConfiguration.Count}}) { - nodes { - __typename - content { - __typename - ... on Issue { - title - closed - } - ... on PullRequest { - title - closed - } - ... on DraftIssue { - title - } - } - } - } - } - } -} -"""; - } - - - public async Task> GetTodosAsync() - { - var todoOptions = _options.Value; - if (todoOptions is null) - { - throw new Exception("Fail to get todos configuration."); - } - - _logger.LogInformation("Username: {}; ProjectNumber: {}; Count: {}", todoOptions.Username, todoOptions.ProjectNumber, todoOptions.Count); - _logger.LogInformation("Getting todos from GitHub GraphQL API..."); - - using var httpClient = new HttpClient(); - - using var requestContent = new StringContent(JsonSerializer.Serialize(new - { - query = CreateGraphQLQuery(todoOptions) - })); - requestContent.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Json, Encoding.UTF8.WebName); - - using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.github.com/graphql"); - request.Content = requestContent; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", todoOptions.Token); - request.Headers.TryAddWithoutValidation("User-Agent", todoOptions.Username); - - using var response = await httpClient.SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - - _logger.LogInformation("GitHub server returned status code: {}", response.StatusCode); - _logger.LogInformation("GitHub server returned body: {}", responseBody); - - if (response.IsSuccessStatusCode) - { - using var responseJson = JsonSerializer.Deserialize(responseBody); - if (responseJson is null) - { - throw new Exception("Fail to deserialize response body."); - } - - var nodes = responseJson.RootElement.GetProperty("data").GetProperty("user").GetProperty("projectV2").GetProperty("items").GetProperty("nodes").EnumerateArray(); - - var result = new List(); - - foreach (var node in nodes) - { - var content = node.GetProperty("content"); - var title = content.GetProperty("title").GetString(); - if (title is null) - { - throw new Exception("Fail to get title."); - } - JsonElement closedElement; - bool closed; - if (content.TryGetProperty("closed", out closedElement)) - { - closed = closedElement.GetBoolean(); - } - else - { - closed = false; - } - - result.Add(new TodoItem - { - Title = title, - Status = closed ? "Done" : "Todo", - Closed = closed, - color = closed ? "green" : "blue" - }); - } - - return result; - } - else - { - const string message = "Fail to get todos from GitHub."; - _logger.LogError(message); - throw new Exception(message); - } - } - } -} \ No newline at end of file diff --git a/docker/crupest-api/CrupestApi/appsettings.json b/docker/crupest-api/CrupestApi/appsettings.json deleted file mode 100644 index 53753bd..0000000 --- a/docker/crupest-api/CrupestApi/appsettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information" - } - }, - "AllowedHosts": "*" -} \ No newline at end of file -- cgit v1.2.3