Skip to content

Commit

Permalink
Add method to get unread count
Browse files Browse the repository at this point in the history
  • Loading branch information
PattaFeuFeu committed Jan 2, 2025
1 parent 4079e66 commit e4d36e5
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package social.bigbone.api.entity

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Capped count of unread notifications.
* @since Mastodon 4.3.0
*/
@Serializable
data class UnreadNotificationCount(
@SerialName("count")
val count: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package social.bigbone.api.method

import social.bigbone.MastodonClient
import social.bigbone.MastodonRequest
import social.bigbone.Parameters
import social.bigbone.api.Pageable
import social.bigbone.api.Range
import social.bigbone.api.entity.Account
import social.bigbone.api.entity.GroupedNotificationsResults
import social.bigbone.api.entity.NotificationType
import social.bigbone.api.entity.UnreadNotificationCount
import social.bigbone.api.exception.BigBoneRequestException

/**
Expand Down Expand Up @@ -146,4 +148,54 @@ class GroupedNotificationMethods(private val client: MastodonClient) {
method = MastodonClient.Method.GET
)
}

/**
* Get the (capped) number of unread notification groups for the current user.
* A notification is considered unread if it is more recent than the notifications read marker.
* Because the count is dependent on the parameters, it is computed every time and is thus a relatively slow operation
* (although faster than getting the full corresponding notifications), therefore the number of returned notifications is capped.
* @param limit Maximum number of results to return. Defaults to 100 notifications. Max 1_000 notifications.
* @param types [NotificationType]s that should count towards unread notifications.
* @param excludeTypes [NotificationType]s that should not count towards unread notifications.
* @param accountId Only count unread notifications received from the specified account.
* @param groupedTypes Restrict which [NotificationType]s can be grouped.
* Use this if there are [NotificationType]s for which your client does not support grouping.
* If omitted, the server will group notifications of all types it supports
* (4.3.0: [NotificationType.FAVOURITE], [NotificationType.FOLLOW], [NotificationType.REBLOG]).
* If you do not want any notification grouping, use [NotificationMethods.getUnreadCount] instead.
* @see <a href="https://docs.joinmastodon.org/methods/grouped_notifications/#unread-group-count">
* Mastodon API documentation: methods/grouped_notifications/#unread-group-count</a>
* @since Mastodon 4.3.0
* @throws IllegalArgumentException if [limit] is set and higher than 1_000.
*/
@Throws(IllegalArgumentException::class)
fun getNumberOfUnreadNotifications(
limit: Int? = null,
types: List<NotificationType>? = null,
excludeTypes: List<NotificationType>? = null,
accountId: String? = null,
groupedTypes: List<NotificationType>? = null
): MastodonRequest<UnreadNotificationCount> {
if (limit != null) {
require(limit <= 1_000) { "Limit must be no larger than 1000 but was $limit" }
}

return client.getMastodonRequest(
endpoint = "$endpoint/unread_count",
method = MastodonClient.Method.GET,
parameters = Parameters().apply {
limit?.let { append("limit", limit) }
accountId?.let { append("account_id", accountId) }
types?.let {
append("types", types.map(NotificationType::apiName))
}
excludeTypes?.let {
append("exclude_types", excludeTypes.map(NotificationType::apiName))
}
groupedTypes?.let {
append("types", groupedTypes.map(NotificationType::apiName))
}
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package social.bigbone.api.method

import social.bigbone.MastodonClient
import social.bigbone.MastodonRequest
import social.bigbone.Parameters
import social.bigbone.api.Pageable
import social.bigbone.api.Range
import social.bigbone.api.entity.Notification
import social.bigbone.api.entity.NotificationType
import social.bigbone.api.entity.UnreadNotificationCount
import social.bigbone.api.exception.BigBoneRequestException

/**
Expand Down Expand Up @@ -82,4 +84,44 @@ class NotificationMethods(private val client: MastodonClient) {
method = MastodonClient.Method.POST
)
}

/**
* Get the (capped) number of unread notification groups for the current user.
* A notification is considered unread if it is more recent than the notifications read marker.
* Because the count is dependent on the parameters, it is computed every time and is thus a relatively slow operation
* (although faster than getting the full corresponding notifications), therefore the number of returned notifications is capped.
* @param limit Maximum number of results to return. Defaults to 100 notifications. Max 1_000 notifications.
* @param types [NotificationType]s that should count towards unread notifications.
* @param excludeTypes [NotificationType]s that should not count towards unread notifications.
* @param accountId Only count unread notifications received from the specified account.
* @see <a href="https://docs.joinmastodon.org/methods/notifications/#unread-count">Mastodon API documentation: methods/notifications/#unread-count</a>
* @since Mastodon 4.3.0
* @throws IllegalArgumentException if [limit] is set and higher than 1_000.
*/
@Throws(IllegalArgumentException::class)
fun getNumberOfUnreadNotifications(
limit: Int? = null,
types: List<NotificationType>? = null,
excludeTypes: List<NotificationType>? = null,
accountId: String? = null
): MastodonRequest<UnreadNotificationCount> {
if (limit != null) {
require(limit <= 1_000) { "Limit must be no larger than 1000" }
}

return client.getMastodonRequest(
endpoint = "$endpoint/unread_count",
method = MastodonClient.Method.GET,
parameters = Parameters().apply {
limit?.let { append("limit", limit) }
accountId?.let { append("account_id", accountId) }
types?.let {
append("types", types.map(NotificationType::apiName))
}
excludeTypes?.let {
append("exclude_types", excludeTypes.map(NotificationType::apiName))
}
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import org.amshove.kluent.shouldContainAll
import org.amshove.kluent.shouldHaveSize
import org.amshove.kluent.shouldNotBeNull
import org.amshove.kluent.shouldNotThrow
import org.amshove.kluent.shouldThrow
import org.amshove.kluent.withMessage
import org.junit.jupiter.api.Test
import social.bigbone.MastodonClient.Method
import social.bigbone.Parameters
Expand Down Expand Up @@ -175,4 +177,49 @@ class GroupedNotificationMethodsTest {
)
}
}

@Test
fun `Given a client returning success, when getting number of unread notifications with parameters, then call endpoint with correct parameter`() {
val client = MockClient.mockClearText("""{"count": 42}""")
val groupedNotificationMethods = GroupedNotificationMethods(client)

groupedNotificationMethods.getNumberOfUnreadNotifications(
limit = 450,
types = listOf(NotificationType.MENTION, NotificationType.REBLOG),
excludeTypes = emptyList(),
accountId = null,
groupedTypes = listOf(NotificationType.REBLOG)
).execute()

val parametersCapturingSlot = slot<Parameters>()
verify {
client.get(
path = "api/v2/notifications/unread_count",
query = capture(parametersCapturingSlot)
)
}
with(parametersCapturingSlot.captured) {
toQuery() shouldBeEqualTo "limit=450&types[]=mention&types[]=reblog&types[]=reblog"
}
}

@Test
fun `Given a client returning success, when getting number of unread notifications, then return UnreadNotificationCount`() {
val client = MockClient.mockClearText("""{"count": 42}""")
val groupedNotificationMethods = GroupedNotificationMethods(client)

val unreadNotifications = groupedNotificationMethods.getNumberOfUnreadNotifications().execute()

unreadNotifications.count shouldBeEqualTo 42
}

@Test
fun `Given a client returning success, when attempting get number of unread notifications with too high limit, then throw IllegalArgumentException`() {
val client = MockClient.mockClearText("""{"count": 42}""")
val groupedNotificationMethods = GroupedNotificationMethods(client)

invoking {
groupedNotificationMethods.getNumberOfUnreadNotifications(limit = 9_001).execute()
} shouldThrow IllegalArgumentException::class withMessage "Limit must be no larger than 1000 but was 9001"
}
}
14 changes: 7 additions & 7 deletions docs/api-coverage/grouped-notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ Receive grouped notifications for activity on your account or statuses.

<a href="https://docs.joinmastodon.org/methods/grouped_notifications/" target="_blank">https://docs.joinmastodon.org/methods/grouped_notifications/</a>

| Method | Description | Status | Comments |
|-------------------------------------------------|-----------------------------------------------------------|---------------------------------|-------------------|
| `GET /api/v2/notifications` | Get all grouped notifications | <img src="/assets/green16.png"> | Fully supported |
| `GET /api/v2/notifications/:group_key` | Get a single notification group | <img src="/assets/green16.png"> | Fully supported |
| `POST /api/v2/notifications/:group_key/dismiss` | Dismiss a single notification group | <img src="/assets/green16.png"> | Fully supported |
| `GET /api/v2/notifications/:group_key/accounts` | Get accounts of all notifications in a notification group | <img src="/assets/green16.png"> | Fully supported |
| `GET /api/v2/notifications/unread_count` | Get the number of unread notifications | <img src="/assets/red16.png"> | Not yet supported |
| Method | Description | Status | Comments |
|-------------------------------------------------|-----------------------------------------------------------|---------------------------------|-----------------|
| `GET /api/v2/notifications` | Get all grouped notifications | <img src="/assets/green16.png"> | Fully supported |
| `GET /api/v2/notifications/:group_key` | Get a single notification group | <img src="/assets/green16.png"> | Fully supported |
| `POST /api/v2/notifications/:group_key/dismiss` | Dismiss a single notification group | <img src="/assets/green16.png"> | Fully supported |
| `GET /api/v2/notifications/:group_key/accounts` | Get accounts of all notifications in a notification group | <img src="/assets/green16.png"> | Fully supported |
| `GET /api/v2/notifications/unread_count` | Get the number of unread notifications | <img src="/assets/green16.png"> | Fully supported |
5 changes: 5 additions & 0 deletions docs/api-coverage/notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ Receive notifications for activity on your account or statuses.
<td style="width:10%;text-align:center;"><img src="/assets/red16.png"></td>
<td style="width:45%;text-align:left;"><b>Will not be implemented</b>.</td>
</tr>
<tr>
<td style="width:45%;text-align:left;"><code>GET /api/v1/notifications/unread_count</code><br>Get the number of unread notifications</td>
<td style="width:10%;text-align:center;"><img src="/assets/green16.png"></td>
<td style="width:45%;text-align:left;">Fully supported.</td>
</tr>
</table>

0 comments on commit e4d36e5

Please sign in to comment.