aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docker/crupest-api/CrupestApi/.dockerignore4
-rw-r--r--docker/crupest-api/CrupestApi/Config/TodosConfiguration.cs15
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj (renamed from docker/crupest-api/CrupestApi/CrupestApi.csproj)1
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseMigrationManager.cs0
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseService.cs0
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Files/CrupestApi.Files.csproj9
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Files/FilesService.cs6
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/CrupestApi.Todos.csproj9
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosConfiguration.cs14
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosService.cs144
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosServiceCollectionExtensions.cs22
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Todos/TodosWebApplicationExtensions.cs41
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.sln28
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi/CrupestApi.csproj14
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi/Program.cs17
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json (renamed from docker/crupest-api/CrupestApi/Properties/launchSettings.json)0
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi/appsettings.json (renamed from docker/crupest-api/CrupestApi/appsettings.json)0
-rw-r--r--docker/crupest-api/CrupestApi/Program.cs59
-rw-r--r--docker/crupest-api/CrupestApi/Services/FileService.cs10
-rw-r--r--docker/crupest-api/CrupestApi/Services/TodoService.cs146
20 files changed, 307 insertions, 232 deletions
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.csproj b/docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj
index 4348979..72a1294 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.csproj
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Database/CrupestApi.Database.csproj
@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
+ <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
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
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseMigrationManager.cs
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
--- /dev/null
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Database/DatabaseService.cs
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 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ <Nullable>enable</Nullable>
+ <ImplicitUsings>enable</ImplicitUsings>
+ </PropertyGroup>
+
+</Project>
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 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ <Nullable>enable</Nullable>
+ <ImplicitUsings>enable</ImplicitUsings>
+ </PropertyGroup>
+
+</Project>
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<TodosConfiguration> _options;
+ private readonly ILogger<TodosService> _logger;
+
+ public TodosService(IOptionsSnapshot<TodosConfiguration> options, ILogger<TodosService> 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<List<TodosItem>> 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<JsonDocument>(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<TodosItem>();
+
+ 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<TodosConfiguration>().BindConfiguration("Todos");
+ services.PostConfigure<TodosConfiguration>(config =>
+ {
+ if (config.Count == 0)
+ {
+ config.Count = 20;
+ }
+ });
+ services.TryAddScoped<TodosService>();
+ 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.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 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+ <ItemGroup>
+ <ProjectReference Include="..\CrupestApi.Todos\CrupestApi.Todos.csproj" />
+ <ProjectReference Include="..\CrupestApi.Files\CrupestApi.Files.csproj" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ <Nullable>enable</Nullable>
+ <ImplicitUsings>enable</ImplicitUsings>
+ </PropertyGroup>
+
+</Project>
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/Properties/launchSettings.json b/docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json
index a4a5cbf..a4a5cbf 100644
--- a/docker/crupest-api/CrupestApi/Properties/launchSettings.json
+++ b/docker/crupest-api/CrupestApi/CrupestApi/Properties/launchSettings.json
diff --git a/docker/crupest-api/CrupestApi/appsettings.json b/docker/crupest-api/CrupestApi/CrupestApi/appsettings.json
index 53753bd..53753bd 100644
--- a/docker/crupest-api/CrupestApi/appsettings.json
+++ b/docker/crupest-api/CrupestApi/CrupestApi/appsettings.json
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<TodoConfiguration>();
- builder.Services.Configure<TodoConfiguration>(builder.Configuration.GetSection("Todos"));
- builder.Services.PostConfigure<TodoConfiguration>(config =>
- {
- if (config.Count is null)
- {
- config.Count = 20;
- }
- });
- builder.Services.TryAddScoped<TodoService>();
-
- 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/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<TodoConfiguration> _options;
- private readonly ILogger<TodoService> _logger;
-
- public TodoService(IOptionsSnapshot<TodoConfiguration> options, ILogger<TodoService> 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<List<TodoItem>> 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<JsonDocument>(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<TodoItem>();
-
- 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