Skip to content

Commit e88ff7a

Browse files
committed
feat: Add support for draft messages
1 parent d396bc3 commit e88ff7a

File tree

3 files changed

+220
-14
lines changed

3 files changed

+220
-14
lines changed

lib/GetStream/StreamChat/Channel.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,4 +640,43 @@ public function updateMemberPartial(string $userId, ?array $set = null, ?array $
640640
];
641641
return $this->client->patch($this->getUrl() . "/member/" . urlencode($userId), $update);
642642
}
643+
644+
/**
645+
* Creates a draft message in the channel.
646+
* @link https://getstream.io/chat/docs/php/drafts/?language=php#creating-a-draft-message
647+
* @throws StreamException
648+
*/
649+
public function createDraft(array $message, string $userId): StreamResponse
650+
{
651+
$payload = ["message" => self::addUser($message, $userId)];
652+
return $this->client->post($this->getUrl() . "/draft", $payload);
653+
}
654+
655+
/**
656+
* Deletes a draft message in the channel.
657+
* @link https://getstream.io/chat/docs/php/drafts/?language=php#deleting-a-draft-message
658+
* @throws StreamException
659+
*/
660+
public function deleteDraft(string $userId, ?string $parentId = null): StreamResponse
661+
{
662+
$params = ["user_id" => $userId];
663+
if ($parentId !== null) {
664+
$params["parent_id"] = $parentId;
665+
}
666+
return $this->client->delete($this->getUrl() . "/draft", $params);
667+
}
668+
669+
/**
670+
* Retrieves a draft message in the channel.
671+
* @link https://getstream.io/chat/docs/php/drafts/?language=php#loading-a-draft-message
672+
* @throws StreamException
673+
*/
674+
public function getDraft(string $userId, ?string $parentId = null): StreamResponse
675+
{
676+
$params = ["user_id" => $userId];
677+
if ($parentId !== null) {
678+
$params["parent_id"] = $parentId;
679+
}
680+
return $this->client->get($this->getUrl() . "/draft", $params);
681+
}
643682
}

lib/GetStream/StreamChat/Client.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,7 @@ public function __construct(string $apiKey, string $apiSecret, ?string $apiVersi
9797
* The baseURL is https://chat.stream-io-api.com regardless of region.
9898
* @deprecated This method will be removed in a future version.
9999
*/
100-
public function setLocation(string $location): void
101-
{
102-
}
100+
public function setLocation(string $location): void {}
103101

104102
/** Returns the base url of the backend.
105103
*/
@@ -1598,4 +1596,28 @@ public function unreadCountsBatch(array $userIds): StreamResponse
15981596
{
15991597
return $this->post("unread_batch", ["user_ids" => $userIds]);
16001598
}
1599+
1600+
/**
1601+
* Queries drafts for a user.
1602+
* @link https://getstream.io/chat/docs/php/drafts/?language=php#querying-draft-messages
1603+
* @throws StreamException
1604+
*/
1605+
public function queryDrafts(string $userId, ?array $filter = null, ?array $sort = null, ?array $options = null): StreamResponse
1606+
{
1607+
$data = ["user_id" => $userId];
1608+
1609+
if ($filter !== null) {
1610+
$data["filter"] = $filter;
1611+
}
1612+
1613+
if ($sort !== null) {
1614+
$data["sort"] = $sort;
1615+
}
1616+
1617+
if ($options !== null) {
1618+
$data = array_merge($data, $options);
1619+
}
1620+
1621+
return $this->post("drafts/query", $data);
1622+
}
16011623
}

tests/integration/IntegrationTest.php

Lines changed: 156 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ public function testPendingMessage()
560560
$msg = ["id" => $msgId, "text" => "hello world"];
561561
$response1 = $this->channel->sendMessage($msg, $this->user1["id"], null, ["pending" => true]);
562562
$this->assertSame($msgId, $response1["message"]["id"]);
563-
563+
564564
$response = $this->client->queryChannels(["id" => $this->channel->id], null, ['user_id' => $this->user1["id"]]);
565565
// check if length of $response["channels"][0]['pending_messages']) is 1
566566
$this->assertSame(1, sizeof($response["channels"][0]['pending_messages']));
@@ -1312,7 +1312,7 @@ public function testImportEnd2End()
13121312
public function testUnreadCounts()
13131313
{
13141314
$this->channel->addMembers([$this->user1["id"]]);
1315-
$msgResp= $this->channel->sendMessage(["text" => "hi"], "random_user_4321");
1315+
$msgResp = $this->channel->sendMessage(["text" => "hi"], "random_user_4321");
13161316

13171317
$resp = $this->client->unreadCounts($this->user1["id"]);
13181318
$this->assertNotEmpty($resp["total_unread_count"]);
@@ -1440,34 +1440,32 @@ public function testSendMessageWithRestrictedVisibility()
14401440
"text" => "secret message",
14411441
"restricted_visibility" => [$this->user1["id"]]
14421442
];
1443-
1444-
1443+
14451444
$response = $this->channel->sendMessage($msg, $this->user1["id"]);
14461445
$this->assertNotNull($response["message"]["restricted_visibility"]);
14471446
$this->assertEquals([$this->user1["id"]], $response["message"]["restricted_visibility"]);
1448-
14491447
}
14501448

14511449
public function testUpdateMessageWithRestrictedVisibility()
14521450
{
14531451
$this->channel->addMembers([$this->user1["id"], $this->user2["id"]]);
1454-
1452+
14551453
// First send a regular message
14561454
$msgId = $this->generateGuid();
14571455
$msg = [
14581456
"id" => $msgId,
14591457
"text" => "original message"
14601458
];
14611459
$response = $this->channel->sendMessage($msg, $this->user1["id"]);
1462-
1460+
14631461
// Then update it with restricted visibility
14641462
$updatedMsg = [
14651463
"id" => $msgId,
14661464
"text" => "updated secret message",
14671465
"restricted_visibility" => [$this->user1["id"]],
14681466
"user" => ["id" => $this->user1["id"]]
14691467
];
1470-
1468+
14711469
$response = $this->client->updateMessage($updatedMsg);
14721470
$this->assertNotNull($response["message"]["restricted_visibility"]);
14731471
$this->assertEquals([$this->user1["id"]], $response["message"]["restricted_visibility"]);
@@ -1476,15 +1474,15 @@ public function testUpdateMessageWithRestrictedVisibility()
14761474
public function testUpdateMessagePartialWithRestrictedVisibility()
14771475
{
14781476
$this->channel->addMembers([$this->user1["id"], $this->user2["id"]]);
1479-
1477+
14801478
// First send a regular message
14811479
$msgId = $this->generateGuid();
14821480
$msg = [
14831481
"id" => $msgId,
14841482
"text" => "original message"
14851483
];
14861484
$response = $this->channel->sendMessage($msg, $this->user1["id"]);
1487-
1485+
14881486
// Then do a partial update with restricted visibility
14891487
$response = $this->client->partialUpdateMessage(
14901488
$msgId,
@@ -1496,7 +1494,7 @@ public function testUpdateMessagePartialWithRestrictedVisibility()
14961494
],
14971495
$this->user1["id"]
14981496
);
1499-
1497+
15001498
$this->assertNotNull($response["message"]["restricted_visibility"]);
15011499
$this->assertEquals([$this->user1["id"]], $response["message"]["restricted_visibility"]);
15021500
}
@@ -1520,4 +1518,151 @@ public function testExportUsers()
15201518
}
15211519
$this->assertSame($response["status"], "completed");
15221520
}
1521+
1522+
public function testCreateDraft()
1523+
{
1524+
$message = ["text" => "This is a draft message"];
1525+
$response = $this->channel->createDraft($message, $this->user1["id"]);
1526+
1527+
$this->assertTrue(array_key_exists("draft", (array)$response));
1528+
$this->assertSame($response["draft"]["message"]["text"], "This is a draft message");
1529+
}
1530+
1531+
public function testGetDraft()
1532+
{
1533+
// First create a draft
1534+
$draftMessage = ["text" => "This is a draft to retrieve"];
1535+
$this->channel->createDraft($draftMessage, $this->user1["id"]);
1536+
1537+
// Then get the draft
1538+
$response = $this->channel->getDraft($this->user1["id"]);
1539+
1540+
$this->assertTrue(array_key_exists("draft", (array)$response));
1541+
$this->assertSame($response["draft"]["message"]["text"], "This is a draft to retrieve");
1542+
$this->assertSame($response["draft"]["channel_cid"], $this->channel->getCID());
1543+
}
1544+
1545+
public function testDeleteDraft()
1546+
{
1547+
// First create a draft
1548+
$draftMessage = ["text" => "This is a draft to delete"];
1549+
$this->channel->createDraft($draftMessage, $this->user1["id"]);
1550+
1551+
// Then delete the draft
1552+
$this->channel->deleteDraft($this->user1["id"]);
1553+
1554+
// Verify it's deleted by trying to get it
1555+
try {
1556+
$this->channel->getDraft($this->user1["id"]);
1557+
$this->fail("Draft should be deleted");
1558+
} catch (\Exception $e) {
1559+
// Expected behavior, draft should not be found
1560+
}
1561+
}
1562+
1563+
public function testThreadDraft()
1564+
{
1565+
// First create a parent message
1566+
$msg = $this->channel->sendMessage(["text" => "Parent message"], $this->user1["id"]);
1567+
$parentId = $msg["message"]["id"];
1568+
1569+
// Create a draft reply
1570+
$draftReply = ["text" => "This is a draft reply", "parent_id" => $parentId];
1571+
$response = $this->channel->createDraft($draftReply, $this->user1["id"]);
1572+
1573+
$this->assertTrue(array_key_exists("draft", (array)$response));
1574+
$this->assertSame($response["draft"]["message"]["text"], "This is a draft reply");
1575+
$this->assertSame($response["draft"]["parent_id"], $parentId);
1576+
1577+
// Get the draft reply
1578+
$response = $this->channel->getDraft($this->user1["id"], $parentId);
1579+
1580+
$this->assertTrue(array_key_exists("draft", (array)$response));
1581+
$this->assertSame($response["draft"]["message"]["text"], "This is a draft reply");
1582+
$this->assertSame($response["draft"]["parent_id"], $parentId);
1583+
1584+
// Delete the draft reply
1585+
$this->channel->deleteDraft($this->user1["id"], $parentId);
1586+
1587+
// Verify it's deleted
1588+
try {
1589+
$this->channel->getDraft($this->user1["id"], $parentId);
1590+
$this->fail("Thread draft should be deleted");
1591+
} catch (\Exception $e) {
1592+
// Expected behavior
1593+
}
1594+
}
1595+
1596+
public function testQueryDrafts()
1597+
{
1598+
// Create multiple drafts in different channels
1599+
$draft1 = ["text" => "Draft in channel 1"];
1600+
$this->channel->createDraft($draft1, $this->user1["id"]);
1601+
1602+
// Create another channel with a draft
1603+
$channel2 = $this->client->Channel("messaging", $this->generateGuid());
1604+
$channel2->create($this->user1["id"]);
1605+
1606+
$draft2 = ["text" => "Draft in channel 2"];
1607+
$channel2->createDraft($draft2, $this->user1["id"]);
1608+
1609+
// Query all drafts for the user
1610+
$response = $this->client->queryDrafts($this->user1["id"]);
1611+
1612+
$this->assertArrayHasKey("drafts", $response);
1613+
$this->assertCount(2, $response["drafts"]);
1614+
1615+
// Query drafts for a specific channel
1616+
$response = $this->client->queryDrafts(
1617+
$this->user1["id"],
1618+
["channel_cid" => $channel2->getCID()]
1619+
);
1620+
1621+
$this->assertArrayHasKey("drafts", $response);
1622+
$this->assertCount(1, $response["drafts"]);
1623+
$draft = $response["drafts"][0];
1624+
$this->assertEquals($channel2->getCID(), $draft["channel_cid"]);
1625+
$this->assertEquals("Draft in channel 2", $draft["message"]["text"]);
1626+
1627+
// Query drafts with sort
1628+
$response = $this->client->queryDrafts(
1629+
$this->user1["id"],
1630+
sort: [["field" => "created_at", "direction" => 1]]
1631+
);
1632+
1633+
$this->assertArrayHasKey("drafts", $response);
1634+
$this->assertCount(2, $response["drafts"]);
1635+
$this->assertEquals($this->channel->getCID(), $response["drafts"][0]["channel_cid"]);
1636+
$this->assertEquals($channel2->getCID(), $response["drafts"][1]["channel_cid"]);
1637+
1638+
// Query drafts with pagination
1639+
$response = $this->client->queryDrafts(
1640+
$this->user1["id"],
1641+
options: ["limit" => 1]
1642+
);
1643+
1644+
$this->assertArrayHasKey("drafts", $response);
1645+
$this->assertCount(1, $response["drafts"]);
1646+
$this->assertEquals($channel2->getCID(), $response["drafts"][0]["channel_cid"]);
1647+
1648+
$this->assertArrayHasKey("next", $response);
1649+
$this->assertNotNull($response["next"]);
1650+
1651+
// Query drafts with pagination and next
1652+
$response = $this->client->queryDrafts(
1653+
$this->user1["id"],
1654+
options: ["limit" => 1, "next" => $response["next"]]
1655+
);
1656+
1657+
$this->assertArrayHasKey("drafts", $response);
1658+
$this->assertCount(1, $response["drafts"]);
1659+
$this->assertEquals($this->channel->getCID(), $response["drafts"][0]["channel_cid"]);
1660+
1661+
// Cleanup
1662+
try {
1663+
$channel2->delete();
1664+
} catch (\Exception $e) {
1665+
// ignore
1666+
}
1667+
}
15231668
}

0 commit comments

Comments
 (0)