Get-NozGraph, Find-NozNote, Measure-NozGarden, Set-NozNoteStatus, Get-NozOrphans — graph edges, Meilisearch search, garden stats, frontmatter status patch, orphan detection from inbound link analysis.
151 lines
6.9 KiB
C#
151 lines
6.9 KiB
C#
using System.Net.Http.Headers;
|
|
using System.Net.Http.Json;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using NozCli.Core.Config;
|
|
using NozCli.Core.Models;
|
|
using NozCli.Core.Serialization;
|
|
|
|
namespace NozCli.Core.Client;
|
|
|
|
public class NozApiClient : IDisposable
|
|
{
|
|
private readonly HttpClient _http;
|
|
|
|
public NozApiClient(LocalConfig cfg)
|
|
{
|
|
_http = new HttpClient
|
|
{
|
|
BaseAddress = new Uri(cfg.ServerUrl.TrimEnd('/') + "/"),
|
|
DefaultRequestVersion = new Version(2, 0),
|
|
};
|
|
_http.DefaultRequestHeaders.Authorization =
|
|
new AuthenticationHeaderValue("Bearer", cfg.Token);
|
|
}
|
|
|
|
public async Task<ServerCapabilities> GetConfigAsync(CancellationToken ct = default)
|
|
{
|
|
var res = await _http.GetFromJsonAsync("api/cli/config", NozJsonContext.Default.JsonElement, ct);
|
|
return new ServerCapabilities(
|
|
Server: res.GetProperty("server").GetString()!,
|
|
Enabled: res.GetProperty("enabled").GetBoolean(),
|
|
AllowPush: res.GetProperty("allow_push").GetBoolean(),
|
|
AllowDelete: res.GetProperty("allow_delete").GetBoolean(),
|
|
AllowVault: res.GetProperty("allow_vault").GetBoolean(),
|
|
AllowRebuild: res.GetProperty("allow_rebuild").GetBoolean()
|
|
);
|
|
}
|
|
|
|
public async Task<List<NoteInfo>> GetNotesAsync(CancellationToken ct = default)
|
|
{
|
|
var res = await _http.GetFromJsonAsync("api/cli/notes", NozJsonContext.Default.JsonElement, ct);
|
|
var notes = res.GetProperty("notes");
|
|
return notes.EnumerateArray().Select(n => new NoteInfo(
|
|
Slug: n.GetProperty("slug").GetString()!,
|
|
Title: n.GetProperty("title").GetString()!,
|
|
Status: n.GetProperty("status").GetString()!,
|
|
Topic: n.GetProperty("topic").GetString()!,
|
|
Lang: n.GetProperty("lang").GetString()!,
|
|
Private: n.GetProperty("private").GetBoolean(),
|
|
Hash: n.TryGetProperty("hash", out var h) ? h.GetString() : null,
|
|
Date: n.TryGetProperty("date", out var d) ? d.GetString() : null
|
|
)).ToList();
|
|
}
|
|
|
|
public async Task<NoteContent> GetNoteAsync(string slug, CancellationToken ct = default)
|
|
{
|
|
var res = await _http.GetFromJsonAsync($"api/cli/notes/{slug}", NozJsonContext.Default.JsonElement, ct);
|
|
return new NoteContent(
|
|
Slug: res.GetProperty("slug").GetString()!,
|
|
Markdown: res.GetProperty("markdown").GetString()!,
|
|
Hash: res.GetProperty("hash").GetString()!
|
|
);
|
|
}
|
|
|
|
public async Task<string> PutNoteAsync(string slug, string markdown, CancellationToken ct = default)
|
|
{
|
|
var body = JsonSerializer.Serialize(new PushBody(markdown), NozJsonContext.Default.PushBody);
|
|
var content = new StringContent(body, Encoding.UTF8, "application/json");
|
|
var res = await _http.PutAsync($"api/cli/notes/{slug}", content, ct);
|
|
res.EnsureSuccessStatusCode();
|
|
var json = await res.Content.ReadFromJsonAsync(NozJsonContext.Default.JsonElement, ct);
|
|
return json.GetProperty("hash").GetString()!;
|
|
}
|
|
|
|
public async Task DeleteNoteAsync(string slug, CancellationToken ct = default)
|
|
{
|
|
var res = await _http.DeleteAsync($"api/cli/notes/{slug}", ct);
|
|
res.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
public async Task<List<TemplateInfo>> GetTemplatesAsync(CancellationToken ct = default)
|
|
{
|
|
var res = await _http.GetFromJsonAsync("api/cli/templates", NozJsonContext.Default.JsonElement, ct);
|
|
return res.GetProperty("templates").EnumerateArray().Select(t => new TemplateInfo(
|
|
Name: t.GetProperty("name").GetString()!,
|
|
Description: t.TryGetProperty("description", out var d) ? d.GetString() : null
|
|
)).ToList();
|
|
}
|
|
|
|
public async Task<TemplateContent?> GetTemplateAsync(string name, CancellationToken ct = default)
|
|
{
|
|
var res = await _http.GetAsync($"api/cli/templates/{Uri.EscapeDataString(name)}", ct);
|
|
if (res.StatusCode == System.Net.HttpStatusCode.NotFound) return null;
|
|
res.EnsureSuccessStatusCode();
|
|
var json = await res.Content.ReadFromJsonAsync(NozJsonContext.Default.JsonElement, ct);
|
|
return new TemplateContent(
|
|
Name: json.GetProperty("name").GetString()!,
|
|
Description: json.TryGetProperty("description", out var d) ? d.GetString() : null,
|
|
Body: json.GetProperty("body").GetString()!
|
|
);
|
|
}
|
|
|
|
public async Task PutFolderIndexAsync(
|
|
string folderPath, string title, string? description = null, CancellationToken ct = default)
|
|
{
|
|
var body = JsonSerializer.Serialize(new FolderBody(title, description), NozJsonContext.Default.FolderBody);
|
|
var content = new StringContent(body, Encoding.UTF8, "application/json");
|
|
var res = await _http.PutAsync($"api/cli/folders/{folderPath}", content, ct);
|
|
res.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
public async Task<GraphData> GetGraphAsync(CancellationToken ct = default)
|
|
{
|
|
var res = await _http.GetFromJsonAsync("api/cli/graph", NozJsonContext.Default.JsonElement, ct);
|
|
var nodes = res.GetProperty("nodes").EnumerateArray().Select(n => new GraphNode(
|
|
Id: n.GetProperty("id").GetString()!,
|
|
Title: n.GetProperty("title").GetString()!,
|
|
Topic: n.GetProperty("topic").GetString()!,
|
|
Status: n.GetProperty("status").GetString()!
|
|
)).ToList();
|
|
var edges = res.GetProperty("edges").EnumerateArray().Select(e => new GraphEdge(
|
|
Source: e.GetProperty("source").GetString()!,
|
|
Target: e.GetProperty("target").GetString()!
|
|
)).ToList();
|
|
return new GraphData(nodes, edges);
|
|
}
|
|
|
|
public async Task<List<SearchHit>> SearchAsync(
|
|
string query, string? topic = null, int limit = 20, CancellationToken ct = default)
|
|
{
|
|
var url = $"api/cli/search?q={Uri.EscapeDataString(query)}&limit={limit}";
|
|
if (topic is not null) url += $"&topic={Uri.EscapeDataString(topic)}";
|
|
var res = await _http.GetFromJsonAsync(url, NozJsonContext.Default.JsonElement, ct);
|
|
return res.GetProperty("hits").EnumerateArray().Select(h => new SearchHit(
|
|
Slug: h.GetProperty("slug").GetString()!,
|
|
Title: h.GetProperty("title").GetString()!,
|
|
Description: h.TryGetProperty("description", out var d) ? d.GetString() : null,
|
|
Topic: h.GetProperty("topic").GetString()!,
|
|
Status: h.GetProperty("status").GetString()!,
|
|
Lang: h.GetProperty("lang").GetString()!
|
|
)).ToList();
|
|
}
|
|
|
|
public async Task RebuildIndexAsync(CancellationToken ct = default)
|
|
{
|
|
var res = await _http.PostAsync("api/cli/rebuild", null, ct);
|
|
res.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
public void Dispose() => _http.Dispose();
|
|
}
|