Skip to content

Commit

Permalink
Merge pull request #7 from DuckDuckStudio/develop
Browse files Browse the repository at this point in the history
feat: 添加用户信息获取功能并更新帮助文档
  • Loading branch information
DuckDuckStudio authored Dec 24, 2024
2 parents 3be8796 + 215a176 commit 21bbeba
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 13 deletions.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,52 @@ GitHubView 是一个用于查看 GitHub 上的信息的命令行工具。目前
| `about` | 查看关于此应用的信息 | / | / |
| `contribute` | 获取指定仓库的前 N 个贡献者信息 (贡献者排行榜) | `ctb 所有者 仓库名 前N个` | `ctb` |
| `labels` | 获取指定仓库的所有标签 | `label 所有者 仓库名` | `label` |
| `user` | 获取指定用户的信息 | `user 用户名` | / |

### 详细介绍
#### help
> 别名: `--help` `-h`
<div style="display: flex; gap: 15px;">
<img src="https://duckduckstudio.github.io/GitHubView/images/README/help.png" alt="显示所有命令的表格" style="height: 75%; width: 75%;">
<p>显示关于此程序的帮助信息。</p>
<p><strong>显示关于此程序的帮助信息。</strong></p>
</div>

#### version
> 别名: `v` `--version` `ver` `-v`
<div style="display: flex; gap: 15px;">
<img src="https://duckduckstudio.github.io/GitHubView/images/README/version.png" alt="显示版本信息的表格" style="height: 75%; width: 75%;">
<p>显示关于此程序的版本信息。<br>在部分终端可以点击内容跳转到详细链接。</p>
<p><strong>显示关于此程序的版本信息。</strong><br>在部分终端可以点击内容跳转到详细链接。</p>
</div>

#### about
<div style="display: flex; gap: 15px;">
<img src="https://duckduckstudio.github.io/GitHubView/images/README/about.png" alt="显示详细信息的表格" style="height: 75%; width: 75%;">
<p>显示关于此程序的详细信息。<br>在部分终端可以点击内容跳转到详细链接。</p>
<p><strong>显示关于此程序的详细信息。</strong><br>在部分终端可以点击内容跳转到详细链接。</p>
</div>

#### contribute
> 别名: `ctb`
<div style="display: flex; gap: 15px;">
<img src="https://duckduckstudio.github.io/GitHubView/images/README/contribute.png" alt="使用示例" style="height: 75%; width: 75%;">
<p>获取指定仓库的前 N 个贡献者信息。<br>换句话说就是获取仓库的贡献数/者排行榜。<br>点击用户名可跳转用户界面。</p>
<p><strong>获取指定仓库的前 N 个贡献者信息。</strong><br>换句话说就是获取仓库的贡献数/者排行榜。<br>点击用户名可跳转用户界面。</p>
</div>

#### labels
> 别名: `label`
<div style="display: flex; gap: 15px;">
<img src="https://duckduckstudio.github.io/GitHubView/images/README/labels.png" alt="使用示例" style="height: 75%; width: 75%;">
<p>获取指定仓库的所有标签。<br><del>相当于<code><a href="https://github.com/DuckDuckStudio/GitHub-Labels-Manager" target="_blank">glm</a> get</code>的表格版。</del></p>
<p><strong>获取指定仓库的所有标签。</strong><br><del>相当于<code><a href="https://github.com/DuckDuckStudio/GitHub-Labels-Manager" target="_blank">glm</a> get</code>的表格版。</del></p>
</div>

#### user

<div style="display: flex; gap: 15px;">
<img src="https://duckduckstudio.github.io/GitHubView/images/README/user.png" alt="使用示例" style="height: 75%; width: 75%;">
<p><strong>获取指定用户的信息。</strong><br>在部分终端可以点击内容跳转到详细链接。<br>如果某项属性为空则不会显示那项属性。</p>
</div>

## 项目状态
Expand Down
Binary file modified docs/images/README/help.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/README/user.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 10 additions & 6 deletions ghv/Command/Help.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ public static void Show()
{
var table = new Table();
table.AddColumn("命令");
table.AddColumn("描述");
table.AddColumn("作用");
table.AddColumn("参数");
table.AddColumn("别名");

table.AddRow("help", "显示帮助信息");
table.AddRow("version", "显示应用程序版本信息");
table.AddRow("about", "显示有关此应用的相关信息");
table.AddRow("contribute", "获取指定仓库的前 N 个贡献者信息");
table.AddRow("labels", "获取指定仓库的所有标签");
// [] 需要转义
table.AddRow("help", "显示帮助信息", "/", "--help -h");
table.AddRow("version", "显示应用程序版本信息", "/", "v --version ver -v");
table.AddRow("about", "显示有关此应用的相关信息", "/", "/");
table.AddRow("contribute", "获取指定仓库的前 N 个贡献者信息", "ctb [[所有者]] [[仓库名]] [[前N个]]", "ctb");
table.AddRow("labels", "获取指定仓库的所有标签", "label [[所有者]] [[仓库名]]", "label");
table.AddRow("user", "获取指定用户的信息", "user [[用户名]]", "/");

AnsiConsole.Write(table);
}
Expand Down
152 changes: 152 additions & 0 deletions ghv/Command/User.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using Spectre.Console;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;

namespace ghv.Command
{
internal class User
{
public static async Task ExecuteAsync(string username)
{
if (string.IsNullOrWhiteSpace(username))
{
username = GetUserInput("请输入用户名:", ValidateUsername);
}

bool userExists = await ValidateUserExists(username);
if (!userExists)
{
AnsiConsole.Markup("[red]该用户不存在,请检查输入的用户名是否正确。[/]\n");
return;
}

await FetchAndDisplayUserInfo(username);
}

private static string GetUserInput(string prompt, Func<string, bool> validator)
{
string input;
do
{
AnsiConsole.Markup("[cyan]? [/]" + prompt + " ");
input = (Console.ReadLine() ?? string.Empty).Trim();

if (!validator(input))
{
AnsiConsole.Markup("[red]输入无效,请重新输入。[/]\n");
}
}
while (string.IsNullOrWhiteSpace(input) || !validator(input));

return input;
}

private static async Task<bool> ValidateUserExists(string username)
{
using HttpClient client = new();
string url = $"https://api.github.com/users/{username}";
client.DefaultRequestHeaders.Add("User-Agent", "CSharpApp");
HttpResponseMessage response = await client.GetAsync(url);
return response.IsSuccessStatusCode;
}

private static async Task FetchAndDisplayUserInfo(string username)
{
using HttpClient client = new();
string url = $"https://api.github.com/users/{username}";
client.DefaultRequestHeaders.Add("User-Agent", "CSharpApp");
HttpResponseMessage response = await client.GetAsync(url);

if (response.IsSuccessStatusCode)
{
string jsonResponse = await response.Content.ReadAsStringAsync();
JsonNode? jsonNode = JsonNode.Parse(jsonResponse);
if (jsonNode == null)
{
AnsiConsole.Markup("[red]无法解析用户数据。[/]\n");
return;
}

var table = new Table();
table.Border(TableBorder.Rounded);
table.BorderColor(Color.Grey);
table.AddColumn(new TableColumn("属性").Centered());
table.AddColumn(new TableColumn("值").Centered());

var propertiesToDisplay = new List<string> { "login", "name", "company", "blog", "location", "email", "bio", "twitter_username" };
var propertyTranslations = new Dictionary<string, string>
{
{ "login", "登录名" },
{ "name", "姓名" },
{ "company", "公司" },
{ "blog", "博客" },
{ "location", "位置" },
{ "email", "电子邮件" },
{ "bio", "简介" },
{ "twitter_username", "Twitter" }
};

string? login = jsonNode["login"]?.ToString();
string? name = jsonNode["name"]?.ToString();
if (!string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(login))
{
string combinedName = $"[link=https://github.com/{login}]{name} ([grey]{login}[/])[/]";
table.AddRow("姓名", combinedName).Border(TableBorder.Square);
}

foreach (var property in jsonNode.AsObject())
{
if (propertiesToDisplay.Contains(property.Key) && property.Key != "login" && property.Key != "name")
{
string propertyName = propertyTranslations.ContainsKey(property.Key) ? propertyTranslations[property.Key] : property.Key;
string propertyValue = Markup.Escape(property.Value?.ToString() ?? string.Empty);

if (!string.IsNullOrWhiteSpace(propertyValue))
{
if (property.Key == "twitter_username")
{
string twitterLink = $"[link=https://twitter.com/{propertyValue}]{propertyValue}[/]";
table.AddRow(propertyName, twitterLink).Border(TableBorder.Square);
}
else if (property.Key == "blog")
{
string blogLink = $"[link={propertyValue}]{propertyValue}[/]";
table.AddRow(propertyName, blogLink).Border(TableBorder.Square);
}
else if (property.Key == "location")
{
string sanitizedLocation = Uri.EscapeDataString(propertyValue);
string locationLink = $"[link=https://www.bing.com/search?q={sanitizedLocation}]{propertyValue}[/]";
table.AddRow(propertyName, locationLink).Border(TableBorder.Square);
}
else if (property.Key == "email")
{
string emailLink = $"[link=mailto:{propertyValue}]{propertyValue}[/]";
table.AddRow(propertyName, emailLink).Border(TableBorder.Square);
}
else
{
table.AddRow(propertyName, propertyValue).Border(TableBorder.Square);
}
}
}
}

table.LeftAligned();

AnsiConsole.Write(table);
}
else
{
AnsiConsole.Markup("[red]无法获取用户信息,请稍后再试。[/]\n");
}
}

private static bool ValidateUsername(string input)
{
if (string.IsNullOrWhiteSpace(input)) return false;
string pattern = @"^[a-zA-Z0-9_-]+$";
return Regex.IsMatch(input, pattern);
}
}
}
6 changes: 5 additions & 1 deletion ghv/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace ghv
{
class Program
{
public const string Version = "1.0.2";
public const string Version = "develop";

static async Task Main(string[] args)
{
Expand Down Expand Up @@ -46,6 +46,10 @@ static async Task Main(string[] args)
repo = args.Length > 2 ? args[2] : string.Empty;
await Labels.ExecuteAsync(owner, repo);
break;
case "user":
string username = args.Length > 1 ? args[1] : string.Empty;
await User.ExecuteAsync(username);
break;
// ...更多命令...
default:
AnsiConsole.Markup("[red]无效的命令。[/]\n");
Expand Down
2 changes: 1 addition & 1 deletion ghv/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"ghv": {
"commandName": "Project",
"commandLineArgs": "ctb DuckDuckStudio Fufu_Tools"
"commandLineArgs": "help"
}
}
}

0 comments on commit 21bbeba

Please sign in to comment.