Skip to content

Commit

Permalink
add support for unread counts (#116)
Browse files Browse the repository at this point in the history
* feat: add support for unread counts

* fix: lint

* chore: drop support for EOL versions, add support for 8.3

* fix: give some time for message to become searchable

* fix: dont run this test locally

* fix: make sure resources are better cleaned up

* fix: try searching in channel

* fix: enable tests for batch unread endpoint

* fix: add tests for unread threads

* chore: update CODEOWNERS
  • Loading branch information
JimmyPettersson85 authored Mar 1, 2024
1 parent cc51d54 commit fd18903
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @ferhatelmas @yaziine
* @yaziine @JimmyPettersson85 @totalimmersion
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ jobs:
strategy:
max-parallel: 1
matrix:
php-versions: ['7.4', '8.0', '8.1', '8.2']
php-versions: ['8.1', '8.2', '8.3']
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0 # gives the commit message linter access to all previous commits

- name: Commit lint
if: ${{ matrix.php-versions == '7.4' }}
if: ${{ matrix.php-versions == '8.1' }}
uses: wagoid/commitlint-github-action@v4

- name: Setup PHP
Expand All @@ -36,11 +36,11 @@ jobs:
run: composer install

- name: Format
if: ${{ matrix.php-versions == '7.4' }}
if: ${{ matrix.php-versions == '8.1' }}
run: vendor/bin/php-cs-fixer fix -v --dry-run --stop-on-violation

- name: Quality
if: ${{ matrix.php-versions == '7.4' }}
if: ${{ matrix.php-versions == '8.1' }}
run: vendor/bin/phan --no-progress-bar

- name: Test
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"docs": "https://getstream.io/chat/docs/php/?language=php"
},
"require": {
"php": ">=7.4",
"php": ">=8.1",
"guzzlehttp/guzzle": "^6.5.8 || ^7.0.1"
},
"require-dev": {
Expand Down
16 changes: 16 additions & 0 deletions lib/GetStream/StreamChat/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -1542,4 +1542,20 @@ public function listImports(array $options = []): StreamResponse
{
return $this->get("imports", $options);
}

/** Get unread counts for a single user.
* @throws StreamException
*/
public function unreadCounts(string $userId): StreamResponse
{
return $this->get("unread", ["user_id" => $userId]);
}

/** Get unread counts for a multiple users at once.
* @throws StreamException
*/
public function unreadCountsBatch(array $userIds): StreamResponse
{
return $this->post("unread_batch", ["user_ids" => $userIds]);
}
}
75 changes: 62 additions & 13 deletions tests/integration/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ protected function setUp(): void
protected function tearDown(): void
{
try {
$this->client->deleteUsers(
[$this->user1['id'], $this->user2['id']],
["user" => "hard", "messages" => "hard"]
);
$this->channel->delete();
$this->client->deleteUser($this->user1['id'], ["user" => "hard", "messages" => "hard"]);
$this->client->deleteUser($this->user2['id'], ["user" => "hard", "messages" => "hard"]);
} catch (\Exception $e) {
// We don't care about cleanup errors
// They're mostly throttlings
Expand Down Expand Up @@ -171,6 +169,7 @@ public function testCheckPush()
$pushResponse = $this->client->checkPush(["message_id" => $response["message"]["id"], "skip_devices" => true, "user_id" => $this->user1["id"]]);

$this->assertTrue(array_key_exists("rendered_message", (array)$pushResponse));
$channel->delete();
}

public function testCheckSqs()
Expand All @@ -187,7 +186,9 @@ public function testCheckSqs()
public function testGuestUser()
{
try {
$response = $this->client->setGuestUser(["user" => ["id" => $this->generateGuid()]]);
$id = $this->generateGuid();
$response = $this->client->setGuestUser(["user" => ["id" => $id]]);
$this->client->deleteUser($id, ["user" => "hard"]);
} catch (\Exception $e) {
// Guest user isn't allowed on all applications
return;
Expand All @@ -202,7 +203,7 @@ public function testUpsertUser()
$response = $this->client->upsertUser($user);
$this->assertTrue(array_key_exists("users", (array)$response));
$this->assertTrue(array_key_exists($user["id"], $response["users"]));
$this->client->deleteUser($user["id"]);
$this->client->deleteUser($user["id"], ["user" => "hard", "messages" => "hard"]);
}

public function testUpsertUsers()
Expand All @@ -211,20 +212,20 @@ public function testUpsertUsers()
$response = $this->client->upsertUsers([$user]);
$this->assertTrue(array_key_exists("users", (array)$response));
$this->assertTrue(array_key_exists($user["id"], $response["users"]));
$this->client->deleteUser($user["id"]);
$this->client->deleteUser($user["id"], ["user" => "hard", "messages" => "hard"]);
}

public function testDeleteUser()
{
$response = $this->client->deleteUser($this->user1["id"]);
$response = $this->client->deleteUser($this->user1["id"], ["user" => "hard", "messages" => "hard"]);
$this->assertTrue(array_key_exists("user", (array)$response));
$this->assertSame($this->user1["id"], $response["user"]["id"]);
}

public function testDeleteUsers()
{
$user = $this->getUser();
$response = $this->client->deleteUsers([$user["id"]], ["user" => "hard"]);
$response = $this->client->deleteUsers([$user["id"]], ["user" => "hard", "messages" => "hard"]);
$this->assertTrue(array_key_exists("task_id", (array)$response));
$taskId = $response["task_id"];

Expand Down Expand Up @@ -667,8 +668,9 @@ public function testQueryMembers()
$response = $channel->queryMembers(["name" => ['$autocomplete' => "bob"]], [], ["limit" => 1]);
$this->assertSame(count($response["members"]), 1);

$this->client->deleteUser($bob["id"], ["user" => "hard", "messages" => "hard"]);
$this->client->deleteUser($bobSponge["id"], ["user" => "hard", "messages" => "hard"]);
$channel->delete();
$this->client->deleteUsers([$bob["id"], $bobSponge["id"]], ["user" => "hard"]);
}

public function testQueryMembersMemberBasedChannel()
Expand All @@ -693,8 +695,9 @@ public function testQueryMembersMemberBasedChannel()
$response = $channel->queryMembers(["name" => ['$autocomplete' => "bob"]], [], ["limit" => 1]);
$this->assertSame(count($response["members"]), 1);

$this->client->deleteUser($bob["id"], ["user" => "hard", "messages" => "hard"]);
$this->client->deleteUser($bobSponge["id"], ["user" => "hard", "messages" => "hard"]);
$channel->delete();
$this->client->deleteUsers([$bob["id"], $bobSponge["id"]], ["user" => "hard"]);
}

public function testDevices()
Expand Down Expand Up @@ -1005,15 +1008,17 @@ public function testSearch()
$this->channel->sendMessage(["text" => "How many syllables are there in " . $query . "?"], $this->user1["id"]);
$this->channel->sendMessage(["text" => "Does 'cious' count as one or two?"], $this->user1["id"]);
$response = $this->client->search(
["type" => "messaging"],
//["type" => "messaging"],
["cid" => $this->channel->getCID()],
$query,
["limit" => 2, "offset" => 0]
);
// searches all channels so make sure at least one is found
$this->assertTrue(count($response['results']) >= 1);
$this->assertTrue(strpos($response['results'][0]['message']['text'], $query) !== false);
$response = $this->client->search(
["type" => "messaging"],
//["type" => "messaging"],
["cid" => $this->channel->getCID()],
"cious",
["limit" => 12, "offset" => 0]
);
Expand Down Expand Up @@ -1158,6 +1163,9 @@ public function testPartialUpdateUsers()
$response = $this->client->queryUsers(["id" => $wally["id"]]);
$this->assertSame($response["users"][0]["shirt"], "striped");
$this->assertFalse(array_key_exists("location", $response["users"][0]));

$this->client->deleteUser($carmen["id"], ["user" => "hard", "messages" => "hard"]);
$this->client->deleteUser($wally["id"], ["user" => "hard", "messages" => "hard"]);
}

public function testChannelMuteUnmute()
Expand Down Expand Up @@ -1240,4 +1248,45 @@ public function testImportEnd2End()
$listResp = $this->client->listImports(['limit' => 1]);
$this->assertNotEmpty($listResp['import_tasks']);
}

public function testUnreadCounts()
{
$this->channel->addMembers([$this->user1["id"]]);
$msgResp= $this->channel->sendMessage(["text" => "hi"], "random_user_4321");

$resp = $this->client->unreadCounts($this->user1["id"]);
$this->assertNotEmpty($resp["total_unread_count"]);
$this->assertEquals(1, $resp["total_unread_count"]);
$this->assertNotEmpty($resp["channels"]);
$this->assertEquals(1, count($resp["channels"]));
$this->assertEquals($this->channel->getCID(), $resp["channels"][0]["channel_id"]);

// test unread thread counts
$this->channel->sendMessage(["parent_id" => $msgResp["message"]["id"], "text" => "hi"], $this->user1["id"]);
$this->channel->sendMessage(["parent_id" => $msgResp["message"]["id"], "text" => "hi"], "random_user_4321");
$resp = $this->client->unreadCounts($this->user1["id"]);
$this->assertNotEmpty($resp["total_unread_threads_count"]);
$this->assertEquals(1, $resp["total_unread_threads_count"]);
}

public function testUnreadCountsBatch()
{
$this->channel->addMembers([$this->user1["id"]]);
$this->channel->addMembers([$this->user2["id"]]);
$msgResp = $this->channel->sendMessage(["text" => "hi"], "random_user_4321");

$resp = $this->client->unreadCountsBatch([$this->user1["id"], $this->user2["id"]]);
$this->assertNotEmpty($resp["counts_by_user"]);
$this->assertEquals(2, count($resp["counts_by_user"]));
$this->assertEquals(1, $resp["counts_by_user"][$this->user1["id"]]["total_unread_count"]);
$this->assertEquals(1, $resp["counts_by_user"][$this->user2["id"]]["total_unread_count"]);

// test unread thread counts
$this->channel->sendMessage(["parent_id" => $msgResp["message"]["id"], "text" => "hi"], $this->user1["id"]);
$this->channel->sendMessage(["parent_id" => $msgResp["message"]["id"], "text" => "hi"], $this->user2["id"]);
$this->channel->sendMessage(["parent_id" => $msgResp["message"]["id"], "text" => "hi"], "random_user_4321");
$resp = $this->client->unreadCountsBatch([$this->user1["id"], $this->user2["id"]]);
$this->assertNotEmpty($resp["counts_by_user"][$this->user1["id"]]["total_unread_threads_count"]);
$this->assertEquals(1, $resp["counts_by_user"][$this->user1["id"]]["total_unread_threads_count"]);
}
}
8 changes: 5 additions & 3 deletions tests/unit/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ public function setUp(): void

public function testClientHostnameWhenNoEnvVarAvailable()
{
$client = new Client('key', 'secret');
$url = $client->buildRequestUrl('x');
$this->assertSame('https://chat.stream-io-api.com/x', $url);
if (!str_contains(getenv('STREAM_BASE_URL'), 'localhost')) {
$client = new Client('key', 'secret');
$url = $client->buildRequestUrl('x');
$this->assertSame('https://chat.stream-io-api.com/x', $url);
}
}

public function testBaseUrlEnvironmentVariables()
Expand Down

0 comments on commit fd18903

Please sign in to comment.