Merge branch 'main' into development

This commit is contained in:
Stone_Red
2024-03-05 19:47:26 +01:00
33 changed files with 730 additions and 9 deletions
+28
View File
@@ -0,0 +1,28 @@
name: Upload nuget package
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x' # SDK Version to use.
source-url: https://nuget.pkg.github.com/Stone-Red-Software/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.NUGET_TOKEN}}
- run: dotnet build --configuration Release src/StoneRed.NetificationApi
- name: Create the package
run: dotnet pack --configuration Release src/StoneRed.NetificationApi
- name: Publish the package to nuget.org
run: dotnet nuget push src/StoneRed.NetificationApi/bin/Release/*.nupkg -k $NUGET_AUTH_TOKEN -s https://api.nuget.org/v3/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.NUGET_TOKEN}}
+95
View File
@@ -1,2 +1,97 @@
# StoneRed.NetificationApi # StoneRed.NetificationApi
> A .NET library for NotificationAPI > A .NET library for NotificationAPI
This is an *unofficial* library for [NotificationAPI](https://www.notificationapi.com/) and attempts to replicate the functionality of the official [Server SDK](https://docs.notificationapi.com/reference/server) and [JS Client SDK](https://docs.notificationapi.com/reference/js-client) as closely as possible.\
(A prebuilt notification widget is not included in this library.)
## Supported Features
**Server:**
- Send all types of notifications
- Retract notifications
- Identify user
- Set user preferences
**Client:**
- Receive `In-App` notification
- Get old notifications
- Get unread notification count
- Clear unread notifications
- Get user preferences
- Update user preferences
## Installation
Package Manager
```bash
Install-Package StoneRed.NetificationApi
```
.NET CLI
```bash
dotnet add package StoneRed.NetificationApi
```
## Usage
### Server
```cs
using StoneRed.NetificationApi.Server;
using StoneRed.NetificationApi.Server.Send;
// Initialize NotificationApiServer
NotificationApiServer notificationApiServer = new NotificationApiServer("<ClientId>", "<ClientSecret>", secureMode: false);
// Construct notification
SendNotificationData sendNotificationData = new SendNotificationData
{
NotificationId = "<NotificationId>",
User = new NotificationUser
{
Id = "<UserId>",
}
};
// Send notification
await notificationApiServer.Send(sendNotificationData);
```
### Client
```cs
using StoneRed.NetificationApi.Client;
using StoneRed.NetificationApi.Client.Models;
// The client is used to receive notifications
NotificationApiClient notificationApiClient = new NotificationApiClient("<UserId>", "<ClientId>");
// Listen for new notifications
notificationApiClient.NewNotificationsReceived += (sender, args) =>
{
Console.WriteLine("New notifications received");
foreach (NotificationReceivedData notificationReceiveData in args.Notifications)
{
Console.WriteLine($"New notification received: {notificationReceiveData.Id}");
}
};
// Listen for unread count
notificationApiClient.UnreadCountReceived += (sender, args) =>
{
Console.WriteLine($"Unread count received: {args.Count}");
};
// Request unread count
notificationApiClient.RequestUnreadCount();
```
For a more sophisticated example, please check out this [example](https://github.com/Stone-Red-Software/StoneRed.NetificationApi/blob/main/src/StoneRed.NetificationApi.Example/Program.cs).
# Third party licenses
- [Websocket.Client](https://github.com/Marfusios/websocket-client) - [MIT](https://github.com/Marfusios/websocket-client/blob/master/LICENSE)
@@ -83,6 +83,7 @@ Console.WriteLine("Send notification");
SendNotificationData sendNotificationData = new SendNotificationData SendNotificationData sendNotificationData = new SendNotificationData
{ {
NotificationId = notificationId, NotificationId = notificationId,
Schedule = DateTime.Now.AddSeconds(10),
User = new NotificationUser User = new NotificationUser
{ {
Id = userId Id = userId
@@ -1,6 +1,16 @@
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents the event arguments for when the count of unread notifications is received.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="CountReceivedEventArgs"/> class with the specified count.
/// </remarks>
/// <param name="count">The count of unread notifications.</param>
public class CountReceivedEventArgs(int count) : EventArgs public class CountReceivedEventArgs(int count) : EventArgs
{ {
/// <summary>
/// Gets the count of unread notifications.
/// </summary>
public int Count { get; } = count; public int Count { get; } = count;
} }
@@ -4,13 +4,32 @@ using System.Diagnostics.CodeAnalysis;
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents a preference for a notification channel.
/// </summary>
public class NotificationChannelPreference public class NotificationChannelPreference
{ {
/// <summary>
/// Gets or sets the channel to set the preference for.
/// </summary>
public NotificationChannel Channel { get; set; } public NotificationChannel Channel { get; set; }
/// <summary>
/// Gets or sets the state of the preference.
/// </summary>
public bool State { get; set; } public bool State { get; set; }
/// <summary>
/// Gets or sets the sub notification id.
/// </summary>
public string? SubNotificationId { get; set; } public string? SubNotificationId { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationChannelPreference"/> class.
/// </summary>
/// <param name="channel">The channel to set the preference for.</param>
/// <param name="state">The state of the preference.</param>
/// <param name="subNotificationId">The sub notification id.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationChannelPreference(NotificationChannel channel, bool state, string? subNotificationId = null) public NotificationChannelPreference(NotificationChannel channel, bool state, string? subNotificationId = null)
{ {
@@ -19,6 +38,9 @@ public class NotificationChannelPreference
SubNotificationId = subNotificationId; SubNotificationId = subNotificationId;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationChannelPreference"/> class.
/// </summary>
public NotificationChannelPreference() public NotificationChannelPreference()
{ {
} }
@@ -1,11 +1,37 @@
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents the data of a notification received.
/// </summary>
public class NotificationReceivedData public class NotificationReceivedData
{ {
/// <summary>
/// Gets or sets the ID of the notification.
/// </summary>
public required string Id { get; set; } public required string Id { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the notification has been seen.
/// </summary>
public required bool Seen { get; set; } public required bool Seen { get; set; }
/// <summary>
/// Gets or sets the title of the notification.
/// </summary>
public required string Title { get; set; } public required string Title { get; set; }
/// <summary>
/// Gets or sets the redirect URL of the notification.
/// </summary>
public required string RedirectURL { get; set; } public required string RedirectURL { get; set; }
/// <summary>
/// Gets or sets the image URL of the notification.
/// </summary>
public required string ImageURL { get; set; } public required string ImageURL { get; set; }
/// <summary>
/// Gets or sets the date of the notification.
/// </summary>
public required DateTime Date { get; set; } public required DateTime Date { get; set; }
} }
@@ -1,9 +1,27 @@
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents a user's preference for a notification.
/// </summary>
public class NotificationUserPreference public class NotificationUserPreference
{ {
/// <summary>
/// Gets or sets the notification ID.
/// </summary>
public required string NotificationId { get; set; } public required string NotificationId { get; set; }
/// <summary>
/// Gets or sets the title of the notification.
/// </summary>
public required string Title { get; set; } public required string Title { get; set; }
/// <summary>
/// Gets or sets the list of settings for the notification.
/// </summary>
public required List<NotificationUserPreferenceSetting> Settings { get; set; } public required List<NotificationUserPreferenceSetting> Settings { get; set; }
/// <summary>
/// Gets or sets the list of sub-notification preferences.
/// </summary>
public required List<object> SubNotificationPreferences { get; set; } public required List<object> SubNotificationPreferences { get; set; }
} }
@@ -2,9 +2,23 @@
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents a user preference setting for a notification channel.
/// </summary>
public class NotificationUserPreferenceSetting public class NotificationUserPreferenceSetting
{ {
/// <summary>
/// Gets or sets the notification channel.
/// </summary>
public required NotificationChannel Channel { get; set; } public required NotificationChannel Channel { get; set; }
/// <summary>
/// Gets or sets the state of the user preference.
/// </summary>
public bool State { get; set; } public bool State { get; set; }
/// <summary>
/// Gets or sets the name of the notification channel.
/// </summary>
public required string ChannelName { get; set; } public required string ChannelName { get; set; }
} }
@@ -1,6 +1,16 @@
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents the event arguments for notifications received.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="NotificationsReceivedEventArgs"/> class.
/// </remarks>
/// <param name="notifications">The list of notifications received.</param>
public class NotificationsReceivedEventArgs(List<NotificationReceivedData> notifications) : EventArgs public class NotificationsReceivedEventArgs(List<NotificationReceivedData> notifications) : EventArgs
{ {
/// <summary>
/// Gets or sets the list of notifications received.
/// </summary>
public List<NotificationReceivedData> Notifications { get; set; } = notifications; public List<NotificationReceivedData> Notifications { get; set; } = notifications;
} }
@@ -1,6 +1,16 @@
namespace StoneRed.NetificationApi.Client.Models; namespace StoneRed.NetificationApi.Client.Models;
/// <summary>
/// Represents the event arguments for when user preferences are received.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="UserPreferencesReceivedEventArgs"/> class.
/// </remarks>
/// <param name="userPreferences">The list of user preferences.</param>
public class UserPreferencesReceivedEventArgs(List<NotificationUserPreference> userPreferences) public class UserPreferencesReceivedEventArgs(List<NotificationUserPreference> userPreferences)
{ {
/// <summary>
/// Gets or sets the list of user preferences.
/// </summary>
public List<NotificationUserPreference> UserPreferences { get; set; } = userPreferences; public List<NotificationUserPreference> UserPreferences { get; set; } = userPreferences;
} }
@@ -13,18 +13,40 @@ using Websocket.Client;
namespace StoneRed.NetificationApi.Client; namespace StoneRed.NetificationApi.Client;
/// <summary>
/// Represents a client for interacting with the Notification API.
/// </summary>
public class NotificationApiClient public class NotificationApiClient
{ {
/// <summary>
/// Event that is raised when requested notifications are received.
/// </summary>
public event EventHandler<NotificationsReceivedEventArgs>? RequestedNotificationsReceived; public event EventHandler<NotificationsReceivedEventArgs>? RequestedNotificationsReceived;
/// <summary>
/// Event that is raised when new notifications are received.
/// </summary>
public event EventHandler<NotificationsReceivedEventArgs>? NewNotificationsReceived; public event EventHandler<NotificationsReceivedEventArgs>? NewNotificationsReceived;
/// <summary>
/// Event that is raised when the unread count is received.
/// </summary>
public event EventHandler<CountReceivedEventArgs>? UnreadCountReceived; public event EventHandler<CountReceivedEventArgs>? UnreadCountReceived;
/// <summary>
/// Event that is raised when user preferences are received.
/// </summary>
public event EventHandler<UserPreferencesReceivedEventArgs>? UserPreferencesReceived; public event EventHandler<UserPreferencesReceivedEventArgs>? UserPreferencesReceived;
private readonly WebsocketClient client; private readonly WebsocketClient client;
/// <summary>
/// Initializes a new instance of the <see cref="NotificationApiClient"/> class.
/// </summary>
/// <param name="userId">The user ID.</param>
/// <param name="clientId">The client ID.</param>
/// <param name="userIdHash">The user ID hash.</param>
/// <param name="baseAddress">The base address of the WebSocket server.</param>
public NotificationApiClient(string userId, string clientId, string? userIdHash = null, string baseAddress = "wss://ws.notificationapi.com") public NotificationApiClient(string userId, string clientId, string? userIdHash = null, string baseAddress = "wss://ws.notificationapi.com")
{ {
UriBuilder uriBuilder = new UriBuilder(baseAddress); UriBuilder uriBuilder = new UriBuilder(baseAddress);
@@ -104,11 +126,20 @@ public class NotificationApiClient
}); });
} }
/// <summary>
/// Starts the Websocket client.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
public Task Start() public Task Start()
{ {
return client.StartOrFail(); return client.StartOrFail();
} }
/// <summary>
/// Requests notifications from the server.
/// </summary>
/// <param name="count">The number of notifications to request.</param>
/// <returns>True if the request was sent successfully; otherwise, false.</returns>
public bool RequestNotifications(int count) public bool RequestNotifications(int count)
{ {
WebsocketMessage<CountPayload> message = new("inapp_web/notifications") WebsocketMessage<CountPayload> message = new("inapp_web/notifications")
@@ -119,6 +150,10 @@ public class NotificationApiClient
return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions)); return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions));
} }
/// <summary>
/// Requests the unread count from the server.
/// </summary>
/// <returns>True if the request was sent successfully; otherwise, false.</returns>
public bool RequestUnreadCount() public bool RequestUnreadCount()
{ {
WebsocketMessage message = new("inapp_web/unread_count"); WebsocketMessage message = new("inapp_web/unread_count");
@@ -126,6 +161,10 @@ public class NotificationApiClient
return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions)); return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions));
} }
/// <summary>
/// Clears the unread count on the server.
/// </summary>
/// <returns>True if the request was sent successfully; otherwise, false.</returns>
public bool ClearUnread() public bool ClearUnread()
{ {
WebsocketMessage message = new("inapp_web/unread_clear"); WebsocketMessage message = new("inapp_web/unread_clear");
@@ -133,6 +172,11 @@ public class NotificationApiClient
return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions)); return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions));
} }
/// <summary>
/// Clears the unread count for a specific notification on the server.
/// </summary>
/// <param name="notificationId">The ID of the notification to clear.</param>
/// <returns>True if the request was sent successfully; otherwise, false.</returns>
public bool ClearUnread(string notificationId) public bool ClearUnread(string notificationId)
{ {
WebsocketMessage<object> message = new("inapp_web/unread_clear") WebsocketMessage<object> message = new("inapp_web/unread_clear")
@@ -146,6 +190,10 @@ public class NotificationApiClient
return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions)); return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions));
} }
/// <summary>
/// Requests the user preferences from the server.
/// </summary>
/// <returns>True if the request was sent successfully; otherwise, false.</returns>
public bool RequestUserPreferences() public bool RequestUserPreferences()
{ {
WebsocketMessage message = new("user_preferences/get_preferences"); WebsocketMessage message = new("user_preferences/get_preferences");
@@ -153,17 +201,23 @@ public class NotificationApiClient
return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions)); return client.Send(JsonSerializer.Serialize(message, Configuration.JsonSerializerOptions));
} }
/// <summary>
/// Patches the user preferences for a specific notification on the server.
/// </summary>
/// <param name="notificationId">The ID of the notification to patch.</param>
/// <param name="channelPreferences">The channel preferences to patch.</param>
/// <returns>True if the request was sent successfully; otherwise, false.</returns>
public bool PatchUserPreferences(string notificationId, params NotificationChannelPreference[] channelPreferences) public bool PatchUserPreferences(string notificationId, params NotificationChannelPreference[] channelPreferences)
{ {
WebsocketMessage<object> message = new("user_preferences/patch_preferences") WebsocketMessage<object> message = new("user_preferences/patch_preferences")
{ {
Payload = new object[] Payload = new object[]
{ {
new new
{ {
notificationId, notificationId,
channelPreferences channelPreferences
} }
} }
}; };
@@ -172,6 +226,10 @@ public class NotificationApiClient
return client.Send(msg); return client.Send(msg);
} }
/// <summary>
/// Stops the Websocket client.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
public Task Stop() public Task Stop()
{ {
return client.StopOrFail(WebSocketCloseStatus.NormalClosure, "Normal closure"); return client.StopOrFail(WebSocketCloseStatus.NormalClosure, "Normal closure");
@@ -3,25 +3,51 @@ using System.Text.Json.Serialization;
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents the data for identifying a user.
/// </summary>
public class IdentifyUserData public class IdentifyUserData
{ {
/// <summary>
/// Gets or sets the user ID.
/// </summary>
[JsonIgnore] [JsonIgnore]
public required string UserId { get; set; } public required string UserId { get; set; }
/// <summary>
/// Gets or sets the email address of the user.
/// </summary>
public string? Email { get; set; } public string? Email { get; set; }
/// <summary>
/// Gets or sets the telephone number of the user.
/// </summary>
[JsonPropertyName("number")] [JsonPropertyName("number")]
public string? TelephoneNumber { get; set; } public string? TelephoneNumber { get; set; }
/// <summary>
/// Gets or sets the list of push tokens for the user.
/// </summary>
public List<NotificationPushToken>? PushTokens { get; set; } public List<NotificationPushToken>? PushTokens { get; set; }
/// <summary>
/// Gets or sets the list of web push tokens for the user.
/// </summary>
public List<NotificationWebPushToken>? WebPushTokens { get; set; } public List<NotificationWebPushToken>? WebPushTokens { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="IdentifyUserData"/> class with the specified user ID.
/// </summary>
/// <param name="userId">The user ID.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public IdentifyUserData(string userId) public IdentifyUserData(string userId)
{ {
UserId = userId; UserId = userId;
} }
/// <summary>
/// Initializes a new instance of the <see cref="IdentifyUserData"/> class.
/// </summary>
public IdentifyUserData() public IdentifyUserData()
{ {
} }
@@ -1,7 +1,17 @@
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents the notification push providers.
/// </summary>
public enum NotificationPushProviders public enum NotificationPushProviders
{ {
/// <summary>
/// Firebase Cloud Messaging.
/// </summary>
FCM, FCM,
/// <summary>
/// Apple Push Notification service.
/// </summary>
APM APM
} }
@@ -2,12 +2,32 @@
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents a notification push token.
/// </summary>
public class NotificationPushToken public class NotificationPushToken
{ {
/// <summary>
/// Gets or sets the type of the notification push provider.
/// </summary>
public required NotificationPushProviders Type { get; set; } public required NotificationPushProviders Type { get; set; }
/// <summary>
/// Gets or sets the token value.
/// </summary>
public required string Token { get; set; } public required string Token { get; set; }
/// <summary>
/// Gets or sets the device associated with the token.
/// </summary>
public required NotificationPushTokenDevice Device { get; set; } public required NotificationPushTokenDevice Device { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationPushToken"/> class.
/// </summary>
/// <param name="type">The type of the notification push provider.</param>
/// <param name="token">The token value.</param>
/// <param name="device">The device associated with the token.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationPushToken(NotificationPushProviders type, string token, NotificationPushTokenDevice device) public NotificationPushToken(NotificationPushProviders type, string token, NotificationPushTokenDevice device)
{ {
@@ -16,6 +36,9 @@ public class NotificationPushToken
Device = device; Device = device;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationPushToken"/> class.
/// </summary>
public NotificationPushToken() public NotificationPushToken()
{ {
} }
@@ -3,27 +3,57 @@ using System.Text.Json.Serialization;
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents a notification push token device.
/// </summary>
public class NotificationPushTokenDevice public class NotificationPushTokenDevice
{ {
/// <summary>
/// Gets or sets the app ID.
/// </summary>
[JsonPropertyName("app_id")] [JsonPropertyName("app_id")]
public string? AppId { get; set; } public string? AppId { get; set; }
/// <summary>
/// Gets or sets the ad ID.
/// </summary>
[JsonPropertyName("ad_id")] [JsonPropertyName("ad_id")]
public string? AdId { get; set; } public string? AdId { get; set; }
/// <summary>
/// Gets or sets the device ID.
/// </summary>
[JsonPropertyName("device_id")] [JsonPropertyName("device_id")]
public required string DeviceId { get; set; } public required string DeviceId { get; set; }
/// <summary>
/// Gets or sets the platform.
/// </summary>
public string? Platform { get; set; } public string? Platform { get; set; }
/// <summary>
/// Gets or sets the manufacturer.
/// </summary>
public string? Manufacturer { get; set; } public string? Manufacturer { get; set; }
/// <summary>
/// Gets or sets the model.
/// </summary>
public string? Model { get; set; } public string? Model { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationPushTokenDevice"/> class.
/// </summary>
/// <param name="deviceId">The device ID.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationPushTokenDevice(string deviceId) public NotificationPushTokenDevice(string deviceId)
{ {
DeviceId = deviceId; DeviceId = deviceId;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationPushTokenDevice"/> class.
/// </summary>
public NotificationPushTokenDevice() public NotificationPushTokenDevice()
{ {
} }
@@ -2,16 +2,29 @@
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents a notification web push token.
/// </summary>
public class NotificationWebPushToken public class NotificationWebPushToken
{ {
/// <summary>
/// Gets or sets the sub property of the notification web push token.
/// </summary>
public required NotificationWebPushTokenSub Sub { get; set; } public required NotificationWebPushTokenSub Sub { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationWebPushToken"/> class with the specified sub.
/// </summary>
/// <param name="sub">The sub value.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationWebPushToken(NotificationWebPushTokenSub sub) public NotificationWebPushToken(NotificationWebPushTokenSub sub)
{ {
Sub = sub; Sub = sub;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationWebPushToken"/> class.
/// </summary>
public NotificationWebPushToken() public NotificationWebPushToken()
{ {
} }
@@ -2,11 +2,26 @@
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents the keys required for a web push notification token.
/// </summary>
public class NotificationWebPushTokenKeys public class NotificationWebPushTokenKeys
{ {
/// <summary>
/// Gets or sets the P256dh key.
/// </summary>
public required string P256dh { get; set; } public required string P256dh { get; set; }
/// <summary>
/// Gets or sets the Auth key.
/// </summary>
public required string Auth { get; set; } public required string Auth { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationWebPushTokenKeys"/> class.
/// </summary>
/// <param name="p256dh">The P256dh key.</param>
/// <param name="auth">The Auth key.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationWebPushTokenKeys(string p256dh, string auth) public NotificationWebPushTokenKeys(string p256dh, string auth)
{ {
@@ -14,6 +29,9 @@ public class NotificationWebPushTokenKeys
Auth = auth; Auth = auth;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationWebPushTokenKeys"/> class.
/// </summary>
public NotificationWebPushTokenKeys() public NotificationWebPushTokenKeys()
{ {
} }
@@ -2,11 +2,26 @@
namespace StoneRed.NetificationApi.Server.IdentifyUser; namespace StoneRed.NetificationApi.Server.IdentifyUser;
/// <summary>
/// Represents a subscription for web push notifications.
/// </summary>
public class NotificationWebPushTokenSub public class NotificationWebPushTokenSub
{ {
/// <summary>
/// Gets or sets the endpoint of the web push notification.
/// </summary>
public required string Endpoint { get; set; } public required string Endpoint { get; set; }
/// <summary>
/// Gets or sets the keys for the web push notification.
/// </summary>
public required NotificationWebPushTokenKeys Keys { get; set; } public required NotificationWebPushTokenKeys Keys { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationWebPushTokenSub"/> class.
/// </summary>
/// <param name="endpoint">The endpoint of the web push notification.</param>
/// <param name="keys">The keys for the web push notification.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationWebPushTokenSub(string endpoint, NotificationWebPushTokenKeys keys) public NotificationWebPushTokenSub(string endpoint, NotificationWebPushTokenKeys keys)
{ {
@@ -14,6 +29,9 @@ public class NotificationWebPushTokenSub
Keys = keys; Keys = keys;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationWebPushTokenSub"/> class.
/// </summary>
public NotificationWebPushTokenSub() public NotificationWebPushTokenSub()
{ {
} }
@@ -9,6 +9,9 @@ using System.Text;
namespace StoneRed.NetificationApi.Server; namespace StoneRed.NetificationApi.Server;
/// <summary>
/// Represents a server for the Notification API.
/// </summary>
public class NotificationApiServer public class NotificationApiServer
{ {
private readonly string clientId; private readonly string clientId;
@@ -16,12 +19,27 @@ public class NotificationApiServer
private readonly bool secureMode; private readonly bool secureMode;
private readonly HttpClient httpClient; private readonly HttpClient httpClient;
/// <summary>
/// Initializes a new instance of the <see cref="NotificationApiServer"/> class.
/// </summary>
/// <param name="clientId">The client ID.</param>
/// <param name="clientSecret">The client secret.</param>
/// <param name="secureMode">Indicates whether secure mode is enabled.</param>
/// <param name="baseAddress">The base address of the API.</param>
public NotificationApiServer(string clientId, string clientSecret, bool secureMode, string baseAddress = "https://api.notificationapi.com") : this(new HttpClient(), clientId, clientSecret, secureMode, baseAddress) public NotificationApiServer(string clientId, string clientSecret, bool secureMode, string baseAddress = "https://api.notificationapi.com") : this(new HttpClient(), clientId, clientSecret, secureMode, baseAddress)
{ {
this.clientId = clientId; this.clientId = clientId;
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationApiServer"/> class.
/// </summary>
/// <param name="httpClient">The HTTP client.</param>
/// <param name="clientId">The client ID.</param>
/// <param name="clientSecret">The client secret.</param>
/// <param name="secureMode">Indicates whether secure mode is enabled.</param>
/// <param name="baseAddress">The base address of the API.</param>
public NotificationApiServer(HttpClient httpClient, string clientId, string clientSecret, bool secureMode, string baseAddress = "https://api.notificationapi.com") public NotificationApiServer(HttpClient httpClient, string clientId, string clientSecret, bool secureMode, string baseAddress = "https://api.notificationapi.com")
{ {
string authToken = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}")); string authToken = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}"));
@@ -35,16 +53,31 @@ public class NotificationApiServer
this.httpClient = httpClient; this.httpClient = httpClient;
} }
/// <summary>
/// Sends a notification.
/// </summary>
/// <param name="sendNotificationData">The data for sending the notification.</param>
/// <returns>The HTTP response message.</returns>
public async Task<HttpResponseMessage> Send(SendNotificationData sendNotificationData) public async Task<HttpResponseMessage> Send(SendNotificationData sendNotificationData)
{ {
return await httpClient.PostAsJsonAsync("sender", sendNotificationData, Configuration.JsonSerializerOptions); return await httpClient.PostAsJsonAsync("sender", sendNotificationData, Configuration.JsonSerializerOptions);
} }
/// <summary>
/// Retracts a notification.
/// </summary>
/// <param name="retractNotificationData">The data for retracting the notification.</param>
/// <returns>The HTTP response message.</returns>
public async Task<HttpResponseMessage> Retract(RetractNotificationData retractNotificationData) public async Task<HttpResponseMessage> Retract(RetractNotificationData retractNotificationData)
{ {
return await httpClient.PostAsJsonAsync("sender/retract", retractNotificationData, Configuration.JsonSerializerOptions); return await httpClient.PostAsJsonAsync("sender/retract", retractNotificationData, Configuration.JsonSerializerOptions);
} }
/// <summary>
/// Identifies a user.
/// </summary>
/// <param name="identifyUserData">The data for identifying the user.</param>
/// <returns>The HTTP response message.</returns>
public async Task<HttpResponseMessage> Identify(IdentifyUserData identifyUserData) public async Task<HttpResponseMessage> Identify(IdentifyUserData identifyUserData)
{ {
string authToken; string authToken;
@@ -75,6 +108,11 @@ public class NotificationApiServer
return await httpClient.SendAsync(request); return await httpClient.SendAsync(request);
} }
/// <summary>
/// Sets user preferences.
/// </summary>
/// <param name="setUserPreferencesData">The data for setting user preferences.</param>
/// <returns>The HTTP response message.</returns>
public async Task<HttpResponseMessage> SetUserPreferences(SetUserPreferencesData setUserPreferencesData) public async Task<HttpResponseMessage> SetUserPreferences(SetUserPreferencesData setUserPreferencesData)
{ {
return await httpClient.PostAsJsonAsync($"user_preferences/{setUserPreferencesData.UserId}", setUserPreferencesData, Configuration.JsonSerializerOptions); return await httpClient.PostAsJsonAsync($"user_preferences/{setUserPreferencesData.UserId}", setUserPreferencesData, Configuration.JsonSerializerOptions);
@@ -2,14 +2,31 @@
namespace StoneRed.NetificationApi.Server.Retract; namespace StoneRed.NetificationApi.Server.Retract;
/// <summary>
/// Represents the data required to retract a notification.
/// </summary>
public class RetractNotificationData public class RetractNotificationData
{ {
/// <summary>
/// Gets or sets the user ID.
/// </summary>
public required string UserId { get; set; } public required string UserId { get; set; }
/// <summary>
/// Gets or sets the notification ID.
/// </summary>
public required string NotificationId { get; set; } public required string NotificationId { get; set; }
/// <summary>
/// Gets or sets the secondary ID.
/// </summary>
public string? SecondaryId { get; set; } public string? SecondaryId { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="RetractNotificationData"/> class.
/// </summary>
/// <param name="userId">The user ID.</param>
/// <param name="notificationId">The notification ID.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public RetractNotificationData(string userId, string notificationId) public RetractNotificationData(string userId, string notificationId)
{ {
@@ -17,6 +34,9 @@ public class RetractNotificationData
NotificationId = notificationId; NotificationId = notificationId;
} }
/// <summary>
/// Initializes a new instance of the <see cref="RetractNotificationData"/> class.
/// </summary>
public RetractNotificationData() public RetractNotificationData()
{ {
} }
@@ -1,18 +1,42 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
/// <summary>
/// Represents the options for sending APN (Apple Push Notification) notifications.
/// </summary>
public class NotificationApnOptions public class NotificationApnOptions
{ {
/// <summary>
/// Gets or sets the expiry time of the notification.
/// </summary>
public int? Expiry { get; set; } public int? Expiry { get; set; }
/// <summary>
/// Gets or sets the priority of the notification.
/// </summary>
public int? Priority { get; set; } public int? Priority { get; set; }
/// <summary>
/// Gets or sets the collapse identifier of the notification.
/// </summary>
public string? CollapseId { get; set; } public string? CollapseId { get; set; }
/// <summary>
/// Gets or sets the thread identifier of the notification.
/// </summary>
public string? ThreadId { get; set; } public string? ThreadId { get; set; }
/// <summary>
/// Gets or sets the badge count of the notification.
/// </summary>
public int? Badge { get; set; } public int? Badge { get; set; }
/// <summary>
/// Gets or sets the sound of the notification.
/// </summary>
public string? Sound { get; set; } public string? Sound { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the notification content is available.
/// </summary>
public bool? ContentAvailable { get; set; } public bool? ContentAvailable { get; set; }
} }
@@ -2,12 +2,26 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
internal class NotificationEmailAttachments /// <summary>
/// Represents an email attachment for notification emails.
/// </summary>
public class NotificationEmailAttachments
{ {
/// <summary>
/// Gets or sets the file name of the attachment.
/// </summary>
public required string FileName { get; set; } public required string FileName { get; set; }
/// <summary>
/// Gets or sets the URL of the attachment.
/// </summary>
public required string Url { get; set; } public required string Url { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationEmailAttachments"/> class.
/// </summary>
/// <param name="fileName">The file name of the attachment.</param>
/// <param name="url">The URL of the attachment.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationEmailAttachments(string fileName, string url) public NotificationEmailAttachments(string fileName, string url)
{ {
@@ -15,6 +29,9 @@ internal class NotificationEmailAttachments
Url = url; Url = url;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationEmailAttachments"/> class.
/// </summary>
public NotificationEmailAttachments() public NotificationEmailAttachments()
{ {
} }
@@ -1,12 +1,27 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
/// <summary>
/// Represents the options for a notification email.
/// </summary>
public class NotificationEmailOptions public class NotificationEmailOptions
{ {
/// <summary>
/// Gets or sets the reply-to addresses for the email.
/// </summary>
public string[]? ReplyToAddresses { get; set; } public string[]? ReplyToAddresses { get; set; }
/// <summary>
/// Gets or sets the CC (carbon copy) addresses for the email.
/// </summary>
public string[]? CcAddresses { get; set; } public string[]? CcAddresses { get; set; }
/// <summary>
/// Gets or sets the BCC (blind carbon copy) addresses for the email.
/// </summary>
public string[]? BccAddresses { get; set; } public string[]? BccAddresses { get; set; }
public string[]? Attachments { get; set; } /// <summary>
/// Gets or sets the attachments for the email.
/// </summary>
public NotificationEmailAttachments[]? Attachments { get; set; }
} }
@@ -1,10 +1,22 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
internal class NotificationFcmAndroidOptions /// <summary>
/// Represents the options for sending FCM notifications to Android devices.
/// </summary>
public class NotificationFcmAndroidOptions
{ {
/// <summary>
/// Gets or sets the collapse key for the notification.
/// </summary>
public string? CollapseKey { get; set; } public string? CollapseKey { get; set; }
/// <summary>
/// Gets or sets the priority of the notification.
/// </summary>
public string? Priority { get; set; } public string? Priority { get; set; }
/// <summary>
/// Gets or sets the time to live (TTL) for the notification.
/// </summary>
public string? Ttl { get; set; } public string? Ttl { get; set; }
} }
@@ -1,6 +1,12 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
internal class NotificationFcmOptions /// <summary>
/// Represents the options for sending FCM notifications.
/// </summary>
public class NotificationFcmOptions
{ {
/// <summary>
/// Gets or sets the Android-specific options for FCM notifications.
/// </summary>
public NotificationFcmAndroidOptions? Android { get; set; } public NotificationFcmAndroidOptions? Android { get; set; }
} }
@@ -1,8 +1,22 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
/// <summary>
/// Represents the options for sending a notification.
/// </summary>
public class NotificationOptions public class NotificationOptions
{ {
/// <summary>
/// Gets or sets the email notification options.
/// </summary>
public NotificationEmailOptions? Email { get; set; } public NotificationEmailOptions? Email { get; set; }
/// <summary>
/// Gets or sets the Apple Push Notification (APN) options.
/// </summary>
public NotificationApnOptions? Apn { get; set; } public NotificationApnOptions? Apn { get; set; }
/// <summary>
/// Gets or sets the Firebase Cloud Messaging (FCM) options.
/// </summary>
public NotificationFcmOptions? Fcm { get; set; }
} }
@@ -3,19 +3,38 @@ using System.Text.Json.Serialization;
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
/// <summary>
/// Represents a notification user.
/// </summary>
public class NotificationUser public class NotificationUser
{ {
/// <summary>
/// Gets or sets the ID of the user.
/// </summary>
public required string Id { get; set; } public required string Id { get; set; }
/// <summary>
/// Gets or sets the email of the user.
/// </summary>
public string? Email { get; set; } public string? Email { get; set; }
/// <summary>
/// Gets or sets the telephone number of the user.
/// </summary>
[JsonPropertyName("number")] [JsonPropertyName("number")]
public string? TelephoneNumber { get; set; } public string? TelephoneNumber { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationUser"/> class.
/// </summary>
public NotificationUser() public NotificationUser()
{ {
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationUser"/> class with the specified ID.
/// </summary>
/// <param name="id">The ID of the user.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationUser(string id) public NotificationUser(string id)
{ {
@@ -2,21 +2,56 @@
namespace StoneRed.NetificationApi.Server.Send; namespace StoneRed.NetificationApi.Server.Send;
/// <summary>
/// Represents the data for sending a notification.
/// </summary>
public class SendNotificationData public class SendNotificationData
{ {
/// <summary>
/// Gets or sets the notification ID.
/// </summary>
public required string NotificationId { get; set; } public required string NotificationId { get; set; }
/// <summary>
/// Gets or sets the sub-notification ID.
/// </summary>
public string? SubNotificationId { get; set; } public string? SubNotificationId { get; set; }
/// <summary>
/// Gets or sets the template ID.
/// </summary>
public string? TemplateId { get; set; } public string? TemplateId { get; set; }
/// <summary>
/// Gets or sets the user for the notification.
/// </summary>
public required NotificationUser User { get; set; } public required NotificationUser User { get; set; }
/// <summary>
/// Gets or sets the merge tags for the notification.
/// </summary>
public Dictionary<string, object>? MergeTags { get; set; } public Dictionary<string, object>? MergeTags { get; set; }
/// <summary>
/// Gets or sets the replace tags for the notification.
/// </summary>
public Dictionary<string, string>? Replace { get; set; } public Dictionary<string, string>? Replace { get; set; }
/// <summary>
/// Gets or sets the time when the notification should be scheduled.
/// </summary>
public DateTime? Schedule { get; set; }
/// <summary>
/// Gets or sets the options for the notification.
/// </summary>
public NotificationOptions? Options { get; set; } public NotificationOptions? Options { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="SendNotificationData"/> class.
/// </summary>
/// <param name="notificationId">The notification ID.</param>
/// <param name="user">The user for the notification.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public SendNotificationData(string notificationId, NotificationUser user) public SendNotificationData(string notificationId, NotificationUser user)
{ {
@@ -24,6 +59,9 @@ public class SendNotificationData
User = user; User = user;
} }
/// <summary>
/// Initializes a new instance of the <see cref="SendNotificationData"/> class.
/// </summary>
public SendNotificationData() public SendNotificationData()
{ {
} }
@@ -4,14 +4,32 @@ using System.Diagnostics.CodeAnalysis;
namespace StoneRed.NetificationApi.Server.SetUserPreferences; namespace StoneRed.NetificationApi.Server.SetUserPreferences;
/// <summary>
/// Represents a notification preference for a user.
/// </summary>
public class NotificationPreference public class NotificationPreference
{ {
/// <summary>
/// Gets or sets the notification ID.
/// </summary>
public required string NotificationId { get; set; } public required string NotificationId { get; set; }
/// <summary>
/// Gets or sets the notification channel.
/// </summary>
public required NotificationChannel Channel { get; set; } public required NotificationChannel Channel { get; set; }
/// <summary>
/// Gets or sets the state of the notification preference.
/// </summary>
public required bool State { get; set; } public required bool State { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationPreference"/> class.
/// </summary>
/// <param name="notificationId">The notification ID.</param>
/// <param name="channel">The notification channel.</param>
/// <param name="state">The state of the notification preference.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public NotificationPreference(string notificationId, NotificationChannel channel, bool state) public NotificationPreference(string notificationId, NotificationChannel channel, bool state)
{ {
@@ -20,6 +38,9 @@ public class NotificationPreference
State = state; State = state;
} }
/// <summary>
/// Initializes a new instance of the <see cref="NotificationPreference"/> class.
/// </summary>
public NotificationPreference() public NotificationPreference()
{ {
} }
@@ -3,13 +3,27 @@ using System.Text.Json.Serialization;
namespace StoneRed.NetificationApi.Server.SetUserPreferences; namespace StoneRed.NetificationApi.Server.SetUserPreferences;
/// <summary>
/// Represents the data for setting user preferences.
/// </summary>
public class SetUserPreferencesData public class SetUserPreferencesData
{ {
/// <summary>
/// Gets or sets the user ID.
/// </summary>
[JsonIgnore] [JsonIgnore]
public required string UserId { get; set; } public required string UserId { get; set; }
/// <summary>
/// Gets or sets the list of notification preferences.
/// </summary>
public required List<NotificationPreference> Preferences { get; set; } public required List<NotificationPreference> Preferences { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="SetUserPreferencesData"/> class.
/// </summary>
/// <param name="userId">The user ID.</param>
/// <param name="preferences">The list of notification preferences.</param>
[SetsRequiredMembers] [SetsRequiredMembers]
public SetUserPreferencesData(string userId, List<NotificationPreference> preferences) public SetUserPreferencesData(string userId, List<NotificationPreference> preferences)
{ {
@@ -17,6 +31,9 @@ public class SetUserPreferencesData
Preferences = preferences; Preferences = preferences;
} }
/// <summary>
/// Initializes a new instance of the <see cref="SetUserPreferencesData"/> class.
/// </summary>
public SetUserPreferencesData() public SetUserPreferencesData()
{ {
} }
@@ -1,11 +1,37 @@
namespace StoneRed.NetificationApi.Shared; namespace StoneRed.NetificationApi.Shared;
/// <summary>
/// Represents the available notification channels.
/// </summary>
public enum NotificationChannel public enum NotificationChannel
{ {
/// <summary>
/// Email notification channel.
/// </summary>
EMAIL, EMAIL,
/// <summary>
/// In-app web notification channel.
/// </summary>
INAPP_WEB, INAPP_WEB,
/// <summary>
/// Web push notification channel.
/// </summary>
WEB_PUSH, WEB_PUSH,
/// <summary>
/// SMS notification channel.
/// </summary>
SMS, SMS,
/// <summary>
/// Push notification channel.
/// </summary>
PUSH, PUSH,
/// <summary>
/// Call notification channel.
/// </summary>
CALL CALL
} }
@@ -4,8 +4,23 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.0.3.0</Version>
<RepositoryUrl>https://github.com/Stone-Red-Software/StoneRed.NetificationApi</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Description>A .NET library for NotificationAPI</Description>
<PackageProjectUrl>https://github.com/Stone-Red-Software/StoneRed.NetificationApi</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Include="..\..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Websocket.Client" Version="5.1.1" /> <PackageReference Include="Websocket.Client" Version="5.1.1" />
</ItemGroup> </ItemGroup>
@@ -3,8 +3,17 @@ using System.Text;
namespace StoneRed.NetificationApi.Utilities; namespace StoneRed.NetificationApi.Utilities;
/// <summary>
/// Provides methods for hashing user IDs.
/// </summary>
public static class UserIdHasher public static class UserIdHasher
{ {
/// <summary>
/// Hashes the specified user ID using the provided client secret.
/// </summary>
/// <param name="userId">The user ID to hash.</param>
/// <param name="clientSecret">The client secret used for hashing.</param>
/// <returns>The hashed user ID.</returns>
public static string Hash(string userId, string clientSecret) public static string Hash(string userId, string clientSecret)
{ {
using HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(clientSecret)); using HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(clientSecret));