diff --git a/SharpQuark/ApiResult/ChannelApiResult.cs b/SharpQuark/ApiResult/ChannelApiResult.cs new file mode 100644 index 0000000000000000000000000000000000000000..73230df8a3fb49778351772b6f7fc49ee6ceec78 --- /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 0000000000000000000000000000000000000000..1879435a919c935a32559057809d33d69de28082 --- /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 b6b71272c62f3df9d876ae8620590831c9cf8fdc..3b3bb5578a6784623d6ed9d049ec3cb2f313783e 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 0000000000000000000000000000000000000000..b207246cd829ddc808f44243d2e1005ac18f75b0 --- /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 3d204d802fde495f839affd908a3872ad96ec708..aecbf88f386facad5d5488cc884e02b815cd55db 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 0000000000000000000000000000000000000000..71346a589c408a9d5d92048c4a4656f10e6a42f0 --- /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 0000000000000000000000000000000000000000..50818858df047f52478e6bc80413c27f28915c26 --- /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 0000000000000000000000000000000000000000..febbe3dd807e0dd240a2cb9a8f875400597cb415 --- /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 0000000000000000000000000000000000000000..94f4fdc649351eca9ef209046991fc89c2357d11 --- /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 0000000000000000000000000000000000000000..2ecffedfecabb110df3dcbae6d3f156ebfced422 --- /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 0000000000000000000000000000000000000000..5cbbcd3309dc4f2ce516b897551fc1e20939b2f9 --- /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 0000000000000000000000000000000000000000..0d0045ce711d3bb8e6820e026fa51d0b074c4606 --- /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 b5786722baf1857ddf4ca6562db329d9880ff4de..b19371d659fcde20007fbb304977b7878686cba5 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 04c4a6c6ee87f697f9e61a5e65a71ca54aa04daf..b8a707548ab7f427eef57f252184c0e1d6c497e7 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 a860e14fa98c9b8b060a25f19a27cce16aae7fb6..33aecba775595c4cd1a39c5e0c6886e6b4aa8416 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);