From 82da0a3619b56133bf73c74b77c748a436cec73b Mon Sep 17 00:00:00 2001
From: Amy <amy@litdevs.org>
Date: Mon, 12 Feb 2024 20:15:09 +0200
Subject: [PATCH] cooked some ids and channels

---
 SharpQuark/ApiResult/ChannelApiResult.cs      | 17 ++++++++++
 .../ApiResult/ChannelMessagesApiResult.cs     | 17 ++++++++++
 SharpQuark/Methods/Auth.cs                    | 17 ++++++++++
 SharpQuark/Methods/Channel.cs                 | 31 +++++++++++++++++
 SharpQuark/Methods/User.cs                    |  3 +-
 SharpQuark/Objects/Channel.cs                 | 23 +++++++++++++
 SharpQuark/Objects/Id/BaseId.cs               | 11 ++++++
 SharpQuark/Objects/Id/ChannelId.cs            | 30 ++++++++++++++++
 SharpQuark/Objects/Id/MessageId.cs            | 32 +++++++++++++++++
 SharpQuark/Objects/Id/QuarkId.cs              | 30 ++++++++++++++++
 SharpQuark/Objects/Id/UserId.cs               | 32 +++++++++++++++++
 SharpQuark/Objects/Message.cs                 | 34 +++++++++++++++++++
 SharpQuark/Objects/User.cs                    |  3 +-
 SharpQuark/Token/TokenCredential.cs           | 10 ++++++
 readme.md                                     |  2 ++
 15 files changed, 290 insertions(+), 2 deletions(-)
 create mode 100644 SharpQuark/ApiResult/ChannelApiResult.cs
 create mode 100644 SharpQuark/ApiResult/ChannelMessagesApiResult.cs
 create mode 100644 SharpQuark/Methods/Channel.cs
 create mode 100644 SharpQuark/Objects/Channel.cs
 create mode 100644 SharpQuark/Objects/Id/BaseId.cs
 create mode 100644 SharpQuark/Objects/Id/ChannelId.cs
 create mode 100644 SharpQuark/Objects/Id/MessageId.cs
 create mode 100644 SharpQuark/Objects/Id/QuarkId.cs
 create mode 100644 SharpQuark/Objects/Id/UserId.cs
 create mode 100644 SharpQuark/Objects/Message.cs

diff --git a/SharpQuark/ApiResult/ChannelApiResult.cs b/SharpQuark/ApiResult/ChannelApiResult.cs
new file mode 100644
index 0000000..73230df
--- /dev/null
+++ b/SharpQuark/ApiResult/ChannelApiResult.cs
@@ -0,0 +1,17 @@
+using Newtonsoft.Json;
+using SharpQuark.Objects;
+
+namespace SharpQuark.ApiResult;
+
+
+public class ChannelApiResult : BaseApiResult
+{
+    [JsonProperty("response")]
+    public new required ChannelResponse Response;
+}
+
+public class ChannelResponse : Response
+{
+    [JsonProperty("channel")]
+    public required Channel Channel;
+}
diff --git a/SharpQuark/ApiResult/ChannelMessagesApiResult.cs b/SharpQuark/ApiResult/ChannelMessagesApiResult.cs
new file mode 100644
index 0000000..1879435
--- /dev/null
+++ b/SharpQuark/ApiResult/ChannelMessagesApiResult.cs
@@ -0,0 +1,17 @@
+using Newtonsoft.Json;
+using SharpQuark.Objects;
+
+namespace SharpQuark.ApiResult;
+
+
+public class ChannelMessagesApiResult : BaseApiResult
+{
+    [JsonProperty("response")]
+    public new required ChannelMessagesResponse Response;
+}
+
+public class ChannelMessagesResponse : Response
+{
+    [JsonProperty("messages")]
+    public required Message[] Messages;
+}
diff --git a/SharpQuark/Methods/Auth.cs b/SharpQuark/Methods/Auth.cs
index b6b7127..3b3bb55 100644
--- a/SharpQuark/Methods/Auth.cs
+++ b/SharpQuark/Methods/Auth.cs
@@ -22,6 +22,23 @@ public partial class Lightquark
         return parsedApiResult ?? throw new Exception("/auth/token API Result is null");
     }
     
+    // /auth/register
+    public async Task<AuthTokenApiResult> AuthRegister(string email, string password, string username)
+    {
+        var rawApiResult = await Call("/auth/register", "POST", new ApiCallOptions
+        {
+            SkipAuth = true,
+            Body = new
+            {
+                email, password, username
+            }
+        });
+
+        var parsedApiResult = JsonConvert.DeserializeObject<AuthTokenApiResult>(rawApiResult);
+        
+        return parsedApiResult ?? throw new Exception("/auth/register API Result is null");
+    }
+    
     // /auth/refresh
     public async Task<AuthRefreshApiResult> AuthRefresh()
     {
diff --git a/SharpQuark/Methods/Channel.cs b/SharpQuark/Methods/Channel.cs
new file mode 100644
index 0000000..b207246
--- /dev/null
+++ b/SharpQuark/Methods/Channel.cs
@@ -0,0 +1,31 @@
+using Newtonsoft.Json;
+using SharpQuark.ApiResult;
+using SharpQuark.Objects;
+using SharpQuark.Objects.Id;
+
+namespace SharpQuark;
+
+public partial class Lightquark
+{
+    public async Task<ChannelApiResult> ChannelById(ChannelId channelId)
+    {
+        var rawApiResult = await Call($"/channel/{channelId}");
+        
+        var parsedApiResult = JsonConvert.DeserializeObject<ChannelApiResult>(rawApiResult);
+
+        if (parsedApiResult != null) parsedApiResult.Response.Channel.Lq = this;
+
+        return parsedApiResult ?? throw new Exception("/channel/{channelId} API Result is null");
+    }
+
+    public async Task<ChannelMessagesApiResult> ChannelMessages(ChannelId channelId)
+    {
+        
+        var rawApiResult = await Call($"/channel/{channelId}/messages");
+        
+        var parsedApiResult = JsonConvert.DeserializeObject<ChannelMessagesApiResult>(rawApiResult);
+
+        return parsedApiResult ?? throw new Exception("/channel/{channelId}/messages API Result is null");
+    }
+    
+}
\ No newline at end of file
diff --git a/SharpQuark/Methods/User.cs b/SharpQuark/Methods/User.cs
index 3d204d8..aecbf88 100644
--- a/SharpQuark/Methods/User.cs
+++ b/SharpQuark/Methods/User.cs
@@ -1,5 +1,6 @@
 using Newtonsoft.Json;
 using SharpQuark.ApiResult;
+using SharpQuark.Objects.Id;
 
 namespace SharpQuark;
 
@@ -16,7 +17,7 @@ public partial class Lightquark
     }
     
     // /user/:userId
-    public async Task<UserApiResult> UserById(string userId)
+    public async Task<UserApiResult> UserById(UserId userId)
     {
         var rawApiResult = await Call($"/user/{userId}");
 
diff --git a/SharpQuark/Objects/Channel.cs b/SharpQuark/Objects/Channel.cs
new file mode 100644
index 0000000..71346a5
--- /dev/null
+++ b/SharpQuark/Objects/Channel.cs
@@ -0,0 +1,23 @@
+using Newtonsoft.Json;
+using SharpQuark.Objects.Id;
+
+namespace SharpQuark.Objects;
+
+public class Channel
+{
+    [JsonProperty("_id")]
+    public required ChannelId Id;
+    [JsonProperty("name")]
+    public required string Name;
+    [JsonProperty("description")]
+    public string Description = string.Empty;
+    [JsonProperty("quark")]
+    public required QuarkId QuarkId;
+
+    [JsonIgnore] public Lightquark? Lq;
+
+    public async Task<Message[]> GetMessages()
+    {
+        return (await Lq.ChannelMessages(Id)).Response.Messages;
+    }
+};
\ No newline at end of file
diff --git a/SharpQuark/Objects/Id/BaseId.cs b/SharpQuark/Objects/Id/BaseId.cs
new file mode 100644
index 0000000..5081885
--- /dev/null
+++ b/SharpQuark/Objects/Id/BaseId.cs
@@ -0,0 +1,11 @@
+namespace SharpQuark.Objects.Id;
+
+public class BaseId(string id)
+{
+    public string Id { get; } = id;
+
+    public override string ToString()
+    {
+        return Id;
+    }
+}
\ No newline at end of file
diff --git a/SharpQuark/Objects/Id/ChannelId.cs b/SharpQuark/Objects/Id/ChannelId.cs
new file mode 100644
index 0000000..febbe3d
--- /dev/null
+++ b/SharpQuark/Objects/Id/ChannelId.cs
@@ -0,0 +1,30 @@
+using Newtonsoft.Json;
+
+namespace SharpQuark.Objects.Id;
+
+[JsonConverter(typeof(ChannelIdConverter))]
+public class ChannelId(string id) : BaseId(id);
+
+public class ChannelIdConverter : JsonConverter
+{
+    public override bool CanConvert(Type objectType)
+    {
+        return objectType == typeof(ChannelId);
+    }
+
+    public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+    {
+        if (reader.TokenType == JsonToken.String)
+        {
+            return new ChannelId((string?)reader.Value ?? string.Empty);
+        }
+        throw new JsonSerializationException("Unexpected token type.");
+    }
+
+    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+    {
+        value ??= string.Empty;
+        var id = (ChannelId)value;
+        writer.WriteValue(id.Id);
+    }
+}
\ No newline at end of file
diff --git a/SharpQuark/Objects/Id/MessageId.cs b/SharpQuark/Objects/Id/MessageId.cs
new file mode 100644
index 0000000..94f4fdc
--- /dev/null
+++ b/SharpQuark/Objects/Id/MessageId.cs
@@ -0,0 +1,32 @@
+using Newtonsoft.Json;
+
+namespace SharpQuark.Objects.Id;
+
+[JsonConverter(typeof(MessageIdConverter))]
+public class MessageId(string id) : BaseId(id);
+
+public class MessageIdConverter : JsonConverter
+{
+    public override bool CanConvert(Type objectType)
+    {
+        return objectType == typeof(MessageId);
+    }
+
+    public override object ReadJson(JsonReader reader, Type objectType, object? existingValue,
+        JsonSerializer serializer)
+    {
+        if (reader.TokenType == JsonToken.String)
+        {
+            return new MessageId((string?)reader.Value ?? string.Empty);
+        }
+
+        throw new JsonSerializationException("Unexpected token type.");
+    }
+
+    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+    {
+        value ??= string.Empty;
+        var id = (MessageId)value;
+        writer.WriteValue(id.Id);
+    }
+}
\ No newline at end of file
diff --git a/SharpQuark/Objects/Id/QuarkId.cs b/SharpQuark/Objects/Id/QuarkId.cs
new file mode 100644
index 0000000..2ecffed
--- /dev/null
+++ b/SharpQuark/Objects/Id/QuarkId.cs
@@ -0,0 +1,30 @@
+using Newtonsoft.Json;
+
+namespace SharpQuark.Objects.Id;
+
+[JsonConverter(typeof(QuarkIdConverter))]
+public class QuarkId(string id) : BaseId(id);
+
+public class QuarkIdConverter : JsonConverter
+{
+    public override bool CanConvert(Type objectType)
+    {
+        return objectType == typeof(QuarkId);
+    }
+
+    public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+    {
+        if (reader.TokenType == JsonToken.String)
+        {
+            return new QuarkId((string?)reader.Value ?? string.Empty);
+        }
+        throw new JsonSerializationException("Unexpected token type.");
+    }
+
+    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+    {
+        value ??= string.Empty;
+        var id = (QuarkId)value;
+        writer.WriteValue(id.Id);
+    }
+}
\ No newline at end of file
diff --git a/SharpQuark/Objects/Id/UserId.cs b/SharpQuark/Objects/Id/UserId.cs
new file mode 100644
index 0000000..5cbbcd3
--- /dev/null
+++ b/SharpQuark/Objects/Id/UserId.cs
@@ -0,0 +1,32 @@
+using Newtonsoft.Json;
+
+namespace SharpQuark.Objects.Id;
+
+[JsonConverter(typeof(UserIdConverter))]
+public class UserId(string id) : BaseId(id);
+
+public class UserIdConverter : JsonConverter
+{
+    public override bool CanConvert(Type objectType)
+    {
+        return objectType == typeof(UserId);
+    }
+
+    public override object ReadJson(JsonReader reader, Type objectType, object? existingValue,
+        JsonSerializer serializer)
+    {
+        if (reader.TokenType == JsonToken.String)
+        {
+            return new UserId((string?)reader.Value ?? string.Empty);
+        }
+
+        throw new JsonSerializationException("Unexpected token type.");
+    }
+
+    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+    {
+        value ??= string.Empty;
+        var id = (UserId)value;
+        writer.WriteValue(id.Id);
+    }
+}
\ No newline at end of file
diff --git a/SharpQuark/Objects/Message.cs b/SharpQuark/Objects/Message.cs
new file mode 100644
index 0000000..0d0045c
--- /dev/null
+++ b/SharpQuark/Objects/Message.cs
@@ -0,0 +1,34 @@
+using Newtonsoft.Json;
+using SharpQuark.Objects.Id;
+
+namespace SharpQuark.Objects;
+
+public class Message
+{
+    [JsonProperty("_id")] 
+    public required MessageId Id;
+    
+    [JsonProperty("authorId")] 
+    public required UserId AuthorId;
+    
+    [JsonProperty("content")]
+    public string Content = string.Empty;
+    
+    [JsonProperty("ua")]
+    public string Agent = "Unknown";
+
+    [JsonProperty("timestamp")] 
+    public required long JsTimestamp;
+
+    [JsonProperty("edited")] 
+    public required bool Edited;
+
+    [JsonProperty("attachments")]
+    public required string[] AttachmentLinks; // TODO: Attachment objects with metadata
+
+    [JsonProperty("specialAttributes")]
+    public object[] SpecialAttributes = [];
+
+    [JsonProperty("author")]
+    public required User Author;
+}
\ No newline at end of file
diff --git a/SharpQuark/Objects/User.cs b/SharpQuark/Objects/User.cs
index b578672..b19371d 100644
--- a/SharpQuark/Objects/User.cs
+++ b/SharpQuark/Objects/User.cs
@@ -1,6 +1,7 @@
 using System.Runtime.Serialization;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Converters;
+using SharpQuark.Objects.Id;
 
 namespace SharpQuark.Objects;
 
@@ -9,7 +10,7 @@ public class User
     [JsonProperty("isBot")]
     public bool IsBot;
     [JsonProperty("_id")]
-    public required string Id;
+    public required UserId Id;
     [JsonProperty("username")]
     public required string Username;
     [JsonProperty("email")]
diff --git a/SharpQuark/Token/TokenCredential.cs b/SharpQuark/Token/TokenCredential.cs
index 04c4a6c..b8a7075 100644
--- a/SharpQuark/Token/TokenCredential.cs
+++ b/SharpQuark/Token/TokenCredential.cs
@@ -30,4 +30,14 @@ public class TokenCredential(AccessToken accessToken, RefreshToken refreshToken)
         var refreshToken = (RefreshToken)Token.From(res.Response.RefreshToken);
         return new TokenCredential(accessToken, refreshToken);
     }
+    
+    public static async Task<TokenCredential> Register(string email, string password, string username, NetworkInformation networkInformation)
+    {
+        // Create temporary Lightquark instance
+        var tempLq = new Lightquark(new TokenCredential(new AccessToken(), new RefreshToken()), networkInformation, null, "v3", true);
+        var res = await tempLq.AuthRegister(email, password, username);
+        var accessToken = (AccessToken)Token.From(res.Response.AccessToken);
+        var refreshToken = (RefreshToken)Token.From(res.Response.RefreshToken);
+        return new TokenCredential(accessToken, refreshToken);
+    }
 }
\ No newline at end of file
diff --git a/readme.md b/readme.md
index a860e14..33aecba 100644
--- a/readme.md
+++ b/readme.md
@@ -18,6 +18,8 @@ var netInfo = await NetworkInformation.GetNetwork("https://equinox.lightquark.ne
 var tokens = await TokenCredential.Login("email", "password", netInfo);
 // Or alternatively stored tokens can be used to get the TokenCredential directly, for example from strings:
 var tokens2 = new TokenCredential((AccessToken)Token.From("access token"), (RefreshToken)Token.From("refresh token"));
+// Another alternative is to register a new account, since that also returns tokens
+var tokens3 = await TokenCredential.Register("email", "password", "username", netInfo);
 
 // With TokenCredential and NetworkInformation we can actually create the Lightquark instance
 var lq = new Lightquark(tokens, netInfo);
-- 
GitLab