Skip to content

Commit

Permalink
fix multi levels bullets, bold, titles 2 and 3.
Browse files Browse the repository at this point in the history
  • Loading branch information
softlion committed Jan 12, 2024
1 parent 99ebe20 commit 1cb6508
Show file tree
Hide file tree
Showing 8 changed files with 1,222 additions and 38 deletions.
1,130 changes: 1,129 additions & 1 deletion NotionSharp.ApiClient.Tests/JsonData/AboutThis.full.children.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion NotionSharp.ApiClient.Tests/JsonData/AboutThis.full.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"id":"c7b44455-3d31-4a5b-b82c-b7e3d85ba585","created_time":"2020-04-30T13:37:00+00:00","last_edited_time":"2023-11-26T17:53:00+00:00","archived":false,"created_by":{"id":"ab9257e1-d027-4494-8792-71d90b63dd35","object":"user"},"last_edited_by":{"id":"ab9257e1-d027-4494-8792-71d90b63dd35","object":"user"},"url":"https://www.notion.so/About-this-c7b444553d314a5bb82cb7e3d85ba585","public_url":"https://wise-spirit-737.notion.site/About-this-c7b444553d314a5bb82cb7e3d85ba585","parent":{"page_id":"18dfbe55-5d7c-416e-9485-7855d4a3949e","type":"page_id"},"properties":{"title":{"title":[{"type":"text","plain_text":"About this","annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"text":{"content":"About this"}}],"id":"title","type":"title"}},"object":"page"}
{"id":"c7b44455-3d31-4a5b-b82c-b7e3d85ba585","created_time":"2020-04-30T13:37:00+00:00","last_edited_time":"2024-01-12T12:34:00+00:00","archived":false,"created_by":{"id":"ab9257e1-d027-4494-8792-71d90b63dd35","object":"user"},"last_edited_by":{"id":"ab9257e1-d027-4494-8792-71d90b63dd35","object":"user"},"url":"https://www.notion.so/About-this-c7b444553d314a5bb82cb7e3d85ba585","public_url":"https://wise-spirit-737.notion.site/About-this-c7b444553d314a5bb82cb7e3d85ba585","parent":{"page_id":"18dfbe55-5d7c-416e-9485-7855d4a3949e","type":"page_id"},"properties":{"title":{"title":[{"type":"text","plain_text":"About this","annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"text":{"content":"About this"}}],"id":"title","type":"title"}},"object":"page"}
23 changes: 8 additions & 15 deletions NotionSharp.ApiClient.Tests/TestNotionBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,34 +253,27 @@ public async Task TestPageAndChildrenDeserialization()
}

[TestMethod]
[Ignore("Run this manually to create the json files")]
//[Ignore("Run this manually to create the json files")]
public async Task TestPageAndChildrenSerialization()
{
var session = new NotionSession(TestUtils.CreateOfficialNotionSessionInfo());
var page = await session.Search(query: "About this", filterOptions: FilterOptions.ObjectPage).FirstAsync();
Assert.AreEqual("About this", page?.Title()?.Title.FirstOrDefault()?.PlainText);

var blocks = await session.GetBlockChildren(page.Id).ToListAsync();
var blockWithChildren = new Queue<Block>(blocks.Where(b => b.HasChildren && BlockTypes.BlocksWithChildren.Contains(b.Type)));
while (blockWithChildren.Count != 0)
{
var block = blockWithChildren.Dequeue();
await session.GetChildren(block);
//recursive
var children = block.Children.Where(b => b.HasChildren && BlockTypes.BlocksWithChildren.Contains(b.Type));
foreach (var child in children)
blockWithChildren.Enqueue(child);
}
var errBlocks = blocks.Where(b => b.HasChildren && !BlockTypes.BlocksWithChildren.Contains(b.Type)).ToList();
Assert.AreEqual(0, errBlocks.Count);
await session.LoadChildBlocks(blocks);

var pageJson = JsonSerializer.Serialize(page, HttpNotionSession.NotionJsonSerializationOptions);
var blocksJson = JsonSerializer.Serialize(blocks, HttpNotionSession.NotionJsonSerializationOptions);
var pageJson = JsonSerializer.Serialize(page, HttpNotionSession.NotionJsonFullSerializationOptions);
var blocksJson = JsonSerializer.Serialize(blocks, HttpNotionSession.NotionJsonFullSerializationOptions);
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
await File.WriteAllTextAsync(Path.Combine(path, "AboutThis.full.json"), pageJson);
await File.WriteAllTextAsync(Path.Combine(path, "AboutThis.full.children.json"), blocksJson);

var page2 = JsonSerializer.Deserialize<Page>(pageJson, HttpNotionSession.NotionJsonSerializationOptions);
var page2 = JsonSerializer.Deserialize<Page>(pageJson, HttpNotionSession.NotionJsonFullSerializationOptions);
Assert.IsNotNull(page2);
var blocks2 = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonSerializationOptions);
var blocks2 = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonFullSerializationOptions);
Assert.IsNotNull(blocks2);
Assert.AreEqual(blocks.Count,blocks2.Count);
}
Expand Down
42 changes: 39 additions & 3 deletions NotionSharp.ApiClient.Tests/TestNotionHtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public async Task TestGetPage()
public async Task TestGetHtml_Link()
{
var blocksJson = await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, "JsonData", "AboutThis.full.children.json"));
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonSerializationOptions);
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonFullSerializationOptions);

var expectedFilePath = "AboutThis.blocks.link.html";
var blockIndex = 0;
Expand All @@ -69,7 +69,7 @@ public async Task TestGetHtml_Link()
public async Task TestGetHtml_Title1()
{
var blocksJson = await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, "JsonData", "AboutThis.full.children.json"));
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonSerializationOptions);
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonFullSerializationOptions);

var blockIndex = 2;

Expand All @@ -83,7 +83,7 @@ public async Task TestGetHtml_Title1()
public async Task TestGetHtml_Title2()
{
var blocksJson = await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, "JsonData", "AboutThis.full.children.json"));
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonSerializationOptions);
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonFullSerializationOptions);

var blockIndex = 3;

Expand All @@ -92,6 +92,42 @@ public async Task TestGetHtml_Title2()
var expectedHtml = """<h2><div class="notion-line">Title 2</div></h2>""" + "\r\n";
Assert.AreEqual(expectedHtml, html);
}

[TestMethod]
public async Task TestGetHtml_Bold()
{
var blocksJson = await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, "JsonData", "AboutThis.full.children.json"));
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonFullSerializationOptions);

var blockIndex = 4;

var block = blocks.Skip(blockIndex).Take(1).ToList();
var html = new HtmlRenderer().GetHtml(block);
var expectedHtml = """<div class="notion-paragraph"><div class="notion-line"><span class=" notion-bold">Bold text</span></div></div>""" + "\r\n";
Assert.AreEqual(expectedHtml, html);
}


[TestMethod]
public async Task TestGetHtml_Bullet_Levels2()
{
var blocksJson = await File.ReadAllTextAsync(Path.Combine(Environment.CurrentDirectory, "JsonData", "AboutThis.full.children.json"));
var blocks = JsonSerializer.Deserialize<List<Block>>(blocksJson, HttpNotionSession.NotionJsonFullSerializationOptions);

var blockIndex = 5;

var block = blocks.Skip(blockIndex).Take(1).ToList();
var html = new HtmlRenderer().GetHtml(block);
var expectedHtml = @"<ul><li><div class=""notion-line"">Level1</div><ul><li><div class=""notion-line"">Level 2</div><ul><li><div class=""notion-line"">Level 3</div><ul><li><div class=""notion-line"">Level 4</div><ul><li><div class=""notion-line"">Level 5</div><ul><li><div class=""notion-line"">Level 6</div><ul><li><div class=""notion-line"">Level 7</div></li></ul>
</li></ul>
</li></ul>
</li></ul>
</li></ul>
</li></ul>
</li></ul>
";
Assert.AreEqual(expectedHtml, html);
}

// [TestMethod]
// public void TestGetHtml_SubBullets()
Expand Down
24 changes: 18 additions & 6 deletions NotionSharp.ApiClient/Lib/HtmlRendering/HtmlRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,23 @@ protected virtual void TransformBulletedListItem(Block block, StringBuilder sb)
{
sb.Append("<ul><li>");
Append(block.BulletedListItem, sb);
if (block?.Children != null)
{
foreach (var child in block.Children)
Transform(child, sb, false);
}
sb.AppendLine("</li></ul>");
}

protected virtual void TransformNumberedListItem(Block block, StringBuilder sb)
{
sb.Append("<ol><li>");
Append(block.NumberedListItem, sb);
if (block?.Children != null)
{
foreach (var child in block.Children)
Transform(child, sb, false);
}
sb.AppendLine("</li></ol>");
}

Expand Down Expand Up @@ -268,29 +278,31 @@ protected virtual StringBuilder Append(RichText? line, StringBuilder sb)
return sb;

sb.Append("<div class=\"notion-line\">");
var tag = line.HasAttribute ? (line.Href != null ? "a" : "span") : null;
var hasAnnotations = line.Annotation?.HasAnnotation == true;
var hasLink = !string.IsNullOrWhiteSpace(line.Href);
var tag = hasLink ? "a" : hasAnnotations ? "span" : null;

if (tag != null)
{
sb.Append("<").Append(tag);

if (line.Href != null)
if (hasLink)
sb.Append(" href=\"").Append(Uri.EscapeUriString(line.Href)).Append("\"");

if (line.HasStyle)
if (hasAnnotations)
{
sb.Append(" class=\"");
if (line.Annotation.Bold)
if (line.Annotation!.Bold)
sb.Append(" notion-bold");
if (line.Annotation.Italic)
sb.Append(" notion-italic");
if (line.Annotation.Strikethrough)
sb.Append(" notion-strikethrough");
if (line.Annotation.Underline)
sb.Append(" notion-underline");
if (line.Annotation.Color != null)
if (line.Annotation.Color is not null and not NotionColor.Default)
sb.Append(" notion-color-").Append(line.Annotation.Color);
if (line.Annotation?.Code != null)
if (line.Annotation.Code)
sb.Append(" notion-code");
sb.Append("\"");
}
Expand Down
29 changes: 22 additions & 7 deletions NotionSharp.ApiClient/Lib/HttpNotionSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,34 @@ public class HttpNotionSession
public static JsonSerializerOptions NotionJsonSerializationOptions { get; } = new (JsonSerializerDefaults.General)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
//PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower,
TypeInfoResolver = NotionJsonContext.Default.WithAddedModifier(AddModifiers) //JsonTypeInfoResolver.Combine(NotionJsonContext.Default) //.WithAddedModifier(AddNestedDerivedTypes))
TypeInfoResolver = NotionJsonContext.Default.WithAddedModifier(ModifierIgnoreBlockChildren)
//JsonTypeInfoResolver.Combine(NotionJsonContext.Default) //.WithAddedModifier(AddNestedDerivedTypes))
};

private static void AddModifiers(JsonTypeInfo jsonTypeInfo)
public static JsonSerializerOptions NotionJsonFullSerializationOptions { get; } = new (JsonSerializerDefaults.General)
{
if (jsonTypeInfo.Type == typeof(PropertyItem))
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower,
TypeInfoResolver = NotionJsonContext.Default
};

private static void ModifierIgnoreBlockChildren(JsonTypeInfo jsonTypeInfo)
{
// if (jsonTypeInfo.Type == typeof(PropertyItem))
// {
// //JsonDerivedType ignores JsonConverter on target type
// var c = jsonTypeInfo.Converter;
// var i = 0;
// }

if (jsonTypeInfo.Type.IsAssignableTo(typeof(Block)))
{
//JsonDerivedType ignores JsonConverter on target type
var c = jsonTypeInfo.Converter;
var i = 0;
var prop = jsonTypeInfo.Properties.FirstOrDefault(p => p.Name == nameof(Block.Children));
if (prop is not null)
prop.ShouldSerialize = (_, _) => false;
}
}

Expand Down
4 changes: 3 additions & 1 deletion NotionSharp.ApiClient/Lib/PublicApi/Model/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ public Block()
public bool Archived { get; init; }
public bool HasChildren { get; init; }

[JsonIgnore]
//Ignore when reading from or writing to Notion api
//Don't ignore for unit testing, as we save and load json files
//Note: Ignored using the Modifiers in HttpNotionSession
public List<Block> Children { get; set; }
#endregion

Expand Down
6 changes: 2 additions & 4 deletions NotionSharp.ApiClient/Lib/PublicApi/Model/Common/RichText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ public class RichText
[JsonPropertyName("annotations")]
public RichTextAnnotation? Annotation { get; init; }

[JsonIgnore]
public bool HasAttribute => Annotation?.HasAnnotation == true || !string.IsNullOrWhiteSpace(Href);
[JsonIgnore]
public bool HasStyle => Annotation?.HasColor == true;
//[JsonIgnore]
//public bool HasStyle => Annotation?.HasColor == true;
#endregion

public RichTextText? Text { get; init; } //type=text
Expand Down

0 comments on commit 1cb6508

Please sign in to comment.