From c1bde9270473c507c490af64a795058c8a4a846b Mon Sep 17 00:00:00 2001 From: Vedant Koditkar Date: Tue, 5 Oct 2021 19:44:39 +0530 Subject: [PATCH 1/4] =?UTF-8?q?Add=20support=20for=20/v1/users/me=20API=20?= =?UTF-8?q?endpoint=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add MeAsync method in IUserClient * Add BotOwner types * Add Unit tests * Update ApiEndpoints.cs --- Src/Notion.Client/Api/ApiEndpoints.cs | 10 ++- Src/Notion.Client/Api/Users/IUsersClient.cs | 6 ++ Src/Notion.Client/Api/Users/UsersClient.cs | 9 +++ Src/Notion.Client/Models/User.cs | 29 +++++++- Test/Notion.UnitTests/Notion.UnitTests.csproj | 6 ++ Test/Notion.UnitTests/UserClientTest.cs | 67 +++++++++++++++++++ .../data/users/MeResponse.json | 13 ++++ .../data/users/MeUserLevelResponse.json | 22 ++++++ 8 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 Test/Notion.UnitTests/data/users/MeResponse.json create mode 100644 Test/Notion.UnitTests/data/users/MeUserLevelResponse.json diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index 8e68e22b..7884123c 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -1,4 +1,6 @@ -namespace Notion.Client +using System; + +namespace Notion.Client { public static class ApiEndpoints { @@ -15,6 +17,12 @@ public static class UsersApiUrls { public static string Retrieve(string userId) => $"/v1/users/{userId}"; public static string List() => "/v1/users"; + + /// + /// Get the for retrieve your token's bot user. + /// + /// Returns a retrieve your token's bot user. + public static string Me() => "/v1/users/me"; } public static class BlocksApiUrls diff --git a/Src/Notion.Client/Api/Users/IUsersClient.cs b/Src/Notion.Client/Api/Users/IUsersClient.cs index 6eab0cde..95427f2b 100644 --- a/Src/Notion.Client/Api/Users/IUsersClient.cs +++ b/Src/Notion.Client/Api/Users/IUsersClient.cs @@ -6,5 +6,11 @@ public interface IUsersClient { Task RetrieveAsync(string userId); Task> ListAsync(); + + /// + /// Retrieves the bot User associated with the API token provided in the authorization header. + /// + /// User object of type bot having an owner field with information about the person who authorized the integration. + Task MeAsync(); } } diff --git a/Src/Notion.Client/Api/Users/UsersClient.cs b/Src/Notion.Client/Api/Users/UsersClient.cs index 0d2e2c90..5c745f72 100644 --- a/Src/Notion.Client/Api/Users/UsersClient.cs +++ b/Src/Notion.Client/Api/Users/UsersClient.cs @@ -21,5 +21,14 @@ public async Task> ListAsync() { return await _client.GetAsync>(UsersApiUrls.List()); } + + /// + /// Retrieves the bot User associated with the API token provided in the authorization header. + /// + /// User object of type bot having an owner field with information about the person who authorized the integration. + public async Task MeAsync() + { + return await _client.GetAsync(UsersApiUrls.Me()); + } } } diff --git a/Src/Notion.Client/Models/User.cs b/Src/Notion.Client/Models/User.cs index ce39e822..64ff25a1 100644 --- a/Src/Notion.Client/Models/User.cs +++ b/Src/Notion.Client/Models/User.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using JsonSubTypes; +using Newtonsoft.Json; namespace Notion.Client { @@ -31,6 +32,32 @@ public class Person public class Bot { + [JsonProperty("owner")] + public IBotOwner Owner { get; set; } + } + + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubType(typeof(UserOwner), "user")] + [JsonSubtypes.KnownSubType(typeof(WorkspaceIntegrationOwner), "workspace")] + public interface IBotOwner + { + [JsonProperty("type")] + string Type { get; set; } + } + + public class WorkspaceIntegrationOwner : IBotOwner + { + public string Type { get; set; } + + [JsonProperty("workspace")] + public bool Workspace { get; set; } + } + + public class UserOwner : IBotOwner + { + public string Type { get; set; } + [JsonProperty("user")] + public User User { get; set; } } } diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index 8382e6bc..3b729bf5 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -81,6 +81,12 @@ Always + + Always + + + Always + Always diff --git a/Test/Notion.UnitTests/UserClientTest.cs b/Test/Notion.UnitTests/UserClientTest.cs index a6ea75ef..d9b27984 100644 --- a/Test/Notion.UnitTests/UserClientTest.cs +++ b/Test/Notion.UnitTests/UserClientTest.cs @@ -78,5 +78,72 @@ public async Task RetrieveUser() user.Person.Email.Should().Be("vedkoditkar@gmail.com"); user.Bot.Should().BeNull(); } + + [Fact] + public async Task RetrieveTokenUser_WorkspaceInternalToken() + { + // Arrange + var jsonData = await File.ReadAllTextAsync("data/users/MeResponse.json"); + + var path = ApiEndpoints.UsersApiUrls.Me(); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( + Response.Create() + .WithStatusCode(200) + .WithBody(jsonData) + ); + + // Act + var user = await _client.MeAsync(); + + // Assert + user.Id.Should().Be("590693f3-797f-4970-98ff-7284106393e5"); + user.Name.Should().Be("Test"); + user.AvatarUrl.Should().BeNull(); + user.Type.Should().Be("bot"); + user.Person.Should().BeNull(); + user.Bot.Should().NotBeNull(); + user.Bot.Owner.Should().BeOfType(); + + var owner = (WorkspaceIntegrationOwner)user.Bot.Owner; + owner.Workspace.Should().BeTrue(); + } + + [Fact] + public async Task RetrieveTokenUser_UserLevelToken() + { + // Arrange + var jsonData = await File.ReadAllTextAsync("data/users/MeUserLevelResponse.json"); + + var path = ApiEndpoints.UsersApiUrls.Me(); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( + Response.Create() + .WithStatusCode(200) + .WithBody(jsonData) + ); + + // Act + var user = await _client.MeAsync(); + + // Assert + user.Id.Should().Be("16d84278-ab0e-484c-9bdd-b35da3bd8905"); + user.Name.Should().Be("pied piper"); + user.AvatarUrl.Should().BeNull(); + user.Type.Should().Be("bot"); + user.Person.Should().BeNull(); + user.Bot.Should().NotBeNull(); + user.Bot.Owner.Should().BeOfType(); + + var owner = (UserOwner)user.Bot.Owner; + owner.User.Id.Should().Be("5389a034-eb5c-47b5-8a9e-f79c99ef166c"); + owner.User.Name.Should().Be("christine makenotion"); + owner.User.AvatarUrl.Should().BeNull(); + owner.User.Type.Should().Be("person"); + owner.User.Person.Email.Should().Be("christine@makenotion.com"); + owner.User.Bot.Should().BeNull(); + } } } diff --git a/Test/Notion.UnitTests/data/users/MeResponse.json b/Test/Notion.UnitTests/data/users/MeResponse.json new file mode 100644 index 00000000..411af097 --- /dev/null +++ b/Test/Notion.UnitTests/data/users/MeResponse.json @@ -0,0 +1,13 @@ +{ + "object": "user", + "id": "590693f3-797f-4970-98ff-7284106393e5", + "name": "Test", + "avatar_url": null, + "type": "bot", + "bot": { + "owner": { + "type": "workspace", + "workspace": true + } + } +} diff --git a/Test/Notion.UnitTests/data/users/MeUserLevelResponse.json b/Test/Notion.UnitTests/data/users/MeUserLevelResponse.json new file mode 100644 index 00000000..cbeec973 --- /dev/null +++ b/Test/Notion.UnitTests/data/users/MeUserLevelResponse.json @@ -0,0 +1,22 @@ +{ + "object": "user", + "id": "16d84278-ab0e-484c-9bdd-b35da3bd8905", + "name": "pied piper", + "avatar_url": null, + "type": "bot", + "bot": { + "owner": { + "type": "user", + "user": { + "object": "user", + "id": "5389a034-eb5c-47b5-8a9e-f79c99ef166c", + "name": "christine makenotion", + "avatar_url": null, + "type": "person", + "person": { + "email": "christine@makenotion.com" + } + } + } + } +} From 297d12ec0497ff26cd6563f0e5858a4c1e47af42 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar Date: Tue, 5 Oct 2021 19:49:02 +0530 Subject: [PATCH 2/4] =?UTF-8?q?Code=20refactor=20=E2=99=BB=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create folder to manage User types 🎨 * Move each class into separate file 🚚 --- Src/Notion.Client/Models/User.cs | 63 ------------------- Src/Notion.Client/Models/User/Bot.cs | 10 +++ .../Models/User/BotOwner/IBotOwner.cs | 14 +++++ .../Models/User/BotOwner/UserOwner.cs | 12 ++++ .../BotOwner/WorkspaceIntegrationOwner.cs | 12 ++++ Src/Notion.Client/Models/User/Person.cs | 10 +++ Src/Notion.Client/Models/User/User.cs | 25 ++++++++ 7 files changed, 83 insertions(+), 63 deletions(-) delete mode 100644 Src/Notion.Client/Models/User.cs create mode 100644 Src/Notion.Client/Models/User/Bot.cs create mode 100644 Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs create mode 100644 Src/Notion.Client/Models/User/BotOwner/UserOwner.cs create mode 100644 Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs create mode 100644 Src/Notion.Client/Models/User/Person.cs create mode 100644 Src/Notion.Client/Models/User/User.cs diff --git a/Src/Notion.Client/Models/User.cs b/Src/Notion.Client/Models/User.cs deleted file mode 100644 index 64ff25a1..00000000 --- a/Src/Notion.Client/Models/User.cs +++ /dev/null @@ -1,63 +0,0 @@ -using JsonSubTypes; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class User : IObject - { - public ObjectType Object => ObjectType.User; - public string Id { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("avatar_url")] - public string AvatarUrl { get; set; } - - [JsonProperty("person")] - public Person Person { get; set; } - - [JsonProperty("bot")] - public Bot Bot { get; set; } - } - - public class Person - { - [JsonProperty("email")] - public string Email { get; set; } - } - - public class Bot - { - [JsonProperty("owner")] - public IBotOwner Owner { get; set; } - } - - [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(UserOwner), "user")] - [JsonSubtypes.KnownSubType(typeof(WorkspaceIntegrationOwner), "workspace")] - public interface IBotOwner - { - [JsonProperty("type")] - string Type { get; set; } - } - - public class WorkspaceIntegrationOwner : IBotOwner - { - public string Type { get; set; } - - [JsonProperty("workspace")] - public bool Workspace { get; set; } - } - - public class UserOwner : IBotOwner - { - public string Type { get; set; } - - [JsonProperty("user")] - public User User { get; set; } - } -} diff --git a/Src/Notion.Client/Models/User/Bot.cs b/Src/Notion.Client/Models/User/Bot.cs new file mode 100644 index 00000000..bd303812 --- /dev/null +++ b/Src/Notion.Client/Models/User/Bot.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class Bot + { + [JsonProperty("owner")] + public IBotOwner Owner { get; set; } + } +} diff --git a/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs b/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs new file mode 100644 index 00000000..e0bfbb11 --- /dev/null +++ b/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs @@ -0,0 +1,14 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubType(typeof(UserOwner), "user")] + [JsonSubtypes.KnownSubType(typeof(WorkspaceIntegrationOwner), "workspace")] + public interface IBotOwner + { + [JsonProperty("type")] + string Type { get; set; } + } +} diff --git a/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs b/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs new file mode 100644 index 00000000..c9c40083 --- /dev/null +++ b/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UserOwner : IBotOwner + { + public string Type { get; set; } + + [JsonProperty("user")] + public User User { get; set; } + } +} diff --git a/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs b/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs new file mode 100644 index 00000000..4171ab31 --- /dev/null +++ b/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class WorkspaceIntegrationOwner : IBotOwner + { + public string Type { get; set; } + + [JsonProperty("workspace")] + public bool Workspace { get; set; } + } +} diff --git a/Src/Notion.Client/Models/User/Person.cs b/Src/Notion.Client/Models/User/Person.cs new file mode 100644 index 00000000..86b81718 --- /dev/null +++ b/Src/Notion.Client/Models/User/Person.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class Person + { + [JsonProperty("email")] + public string Email { get; set; } + } +} diff --git a/Src/Notion.Client/Models/User/User.cs b/Src/Notion.Client/Models/User/User.cs new file mode 100644 index 00000000..7f336929 --- /dev/null +++ b/Src/Notion.Client/Models/User/User.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class User : IObject + { + public ObjectType Object => ObjectType.User; + public string Id { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("avatar_url")] + public string AvatarUrl { get; set; } + + [JsonProperty("person")] + public Person Person { get; set; } + + [JsonProperty("bot")] + public Bot Bot { get; set; } + } +} From ff4f036971a79c49990aed92a06687783fdc5bb4 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar Date: Tue, 5 Oct 2021 19:49:43 +0530 Subject: [PATCH 3/4] =?UTF-8?q?Run=20dotnet=20format=20=F0=9F=9A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Notion.Client/Models/User/Bot.cs | 2 +- Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs | 2 +- Src/Notion.Client/Models/User/BotOwner/UserOwner.cs | 2 +- .../Models/User/BotOwner/WorkspaceIntegrationOwner.cs | 2 +- Src/Notion.Client/Models/User/Person.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Src/Notion.Client/Models/User/Bot.cs b/Src/Notion.Client/Models/User/Bot.cs index bd303812..2eaf6420 100644 --- a/Src/Notion.Client/Models/User/Bot.cs +++ b/Src/Notion.Client/Models/User/Bot.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { diff --git a/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs b/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs index e0bfbb11..61a7a887 100644 --- a/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs +++ b/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs @@ -1,4 +1,4 @@ -using JsonSubTypes; +using JsonSubTypes; using Newtonsoft.Json; namespace Notion.Client diff --git a/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs b/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs index c9c40083..40d69867 100644 --- a/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs +++ b/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { diff --git a/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs b/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs index 4171ab31..78a84f6f 100644 --- a/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs +++ b/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { diff --git a/Src/Notion.Client/Models/User/Person.cs b/Src/Notion.Client/Models/User/Person.cs index 86b81718..621f3b48 100644 --- a/Src/Notion.Client/Models/User/Person.cs +++ b/Src/Notion.Client/Models/User/Person.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { From 4d828bf3cfc3ad3422dcffb2e7614eece483f1da Mon Sep 17 00:00:00 2001 From: Vedant Koditkar Date: Tue, 5 Oct 2021 19:54:26 +0530 Subject: [PATCH 4/4] =?UTF-8?q?Update=20readme=20=F0=9F=93=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 900a2451..4c09f984 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ var complexFiler = new CompoundFilter( - [x] Users - [x] Retrieve a User - [x] List all users + - [x] Retrieve your token's bot user - [x] Search ## Contribution Guideline diff --git a/docs/README.md b/docs/README.md index 4088b54b..542fe472 100644 --- a/docs/README.md +++ b/docs/README.md @@ -84,6 +84,7 @@ var complexFiler = new CompoundFilter( - [x] Users - [x] Retrieve a User - [x] List all users + - [x] Retrieve your token's bot user - [x] Search ## Contribution Guideline