Skip to content

Commit ac44302

Browse files
authored
feat: improved some apis (#169)
BREAKING CHANGE: - `PartialUpdateMessage` method has a new signature - `Truncatechannel` method has a new signature - `AddMembers` method has a new signature - `MarkRead` method has a new signature - `UpdateCommand` method has a new signature - `PartialUpdateMessage` method has a new signature - `MuteUser` method has a new signature - `MuteUsers` method has a new signature - `FlagUser` method has a new signature - `ExportUser` method has a new signature - `DeactivateUser` method has a new signature - `ReactivateUser` method has a new signature - `DeleteUser` method has a new signature - `BanUser` methods have a new signature - `UnbanUser` methods have a new signature - `ShadowBan` methods have a new signature
1 parent c76c8f5 commit ac44302

File tree

11 files changed

+584
-368
lines changed

11 files changed

+584
-368
lines changed

async_tasks_test.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,11 @@ func TestClient_ExportChannels(t *testing.T) {
9090
chMembers = append(chMembers, ch2.Members...)
9191

9292
defer func() {
93-
options := map[string][]string{
94-
"delete_conversation_channels": {"true"},
95-
"mark_messages_deleted": {"true"},
96-
"hard_delete": {"true"},
97-
}
98-
9993
for _, u := range chMembers {
100-
_, _ = c.DeleteUser(context.Background(), u.UserID, options)
94+
_, _ = c.DeleteUser(context.Background(), u.UserID,
95+
DeleteUserWithDeleteConversations(),
96+
DeleteUserWithHardDelete(),
97+
DeleteUserWithMarkMessagesDeleted())
10198
}
10299
}()
103100

ban.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package stream_chat
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"errors"
7+
"net/http"
8+
"net/url"
9+
"time"
10+
)
11+
12+
// BanUser bans targetID.
13+
func (c *Client) BanUser(ctx context.Context, targetID, bannedBy string, options ...BanOption) (*Response, error) {
14+
switch {
15+
case targetID == "":
16+
return nil, errors.New("targetID should not be empty")
17+
case bannedBy == "":
18+
return nil, errors.New("bannedBy should not be empty")
19+
}
20+
21+
opts := &banOptions{
22+
TargetUserID: targetID,
23+
BannedBy: bannedBy,
24+
}
25+
26+
for _, fn := range options {
27+
fn(opts)
28+
}
29+
30+
var resp Response
31+
err := c.makeRequest(ctx, http.MethodPost, "moderation/ban", nil, opts, &resp)
32+
return &resp, err
33+
}
34+
35+
// UnBanUser removes the ban for targetID.
36+
func (c *Client) UnBanUser(ctx context.Context, targetID string) (*Response, error) {
37+
if targetID == "" {
38+
return nil, errors.New("targetID should not be empty")
39+
}
40+
41+
params := url.Values{}
42+
params.Set("target_user_id", targetID)
43+
44+
var resp Response
45+
err := c.makeRequest(ctx, http.MethodDelete, "moderation/ban", params, nil, &resp)
46+
return &resp, err
47+
}
48+
49+
// ShadowBan shadow bans targetID.
50+
func (c *Client) ShadowBan(ctx context.Context, targetID, bannedByID string, options ...BanOption) (*Response, error) {
51+
options = append(options, banWithShadow())
52+
return c.BanUser(ctx, targetID, bannedByID, options...)
53+
}
54+
55+
// BanUser bans targetID on the channel ch.
56+
func (ch *Channel) BanUser(ctx context.Context, targetID, bannedBy string, options ...BanOption) (*Response, error) {
57+
options = append(options, banFromChannel(ch.Type, ch.ID))
58+
return ch.client.BanUser(ctx, targetID, bannedBy, options...)
59+
}
60+
61+
// UnBanUser removes the ban for targetID from the channel ch.
62+
func (ch *Channel) UnBanUser(ctx context.Context, targetID string) (*Response, error) {
63+
if targetID == "" {
64+
return nil, errors.New("targetID should not be empty")
65+
}
66+
67+
params := url.Values{}
68+
params.Set("target_user_id", targetID)
69+
params.Set("id", ch.ID)
70+
params.Set("type", ch.Type)
71+
72+
var resp Response
73+
err := ch.client.makeRequest(ctx, http.MethodDelete, "moderation/ban", params, nil, &resp)
74+
return &resp, err
75+
}
76+
77+
// ShadowBan shadow bans targetID on the channel ch.
78+
func (ch *Channel) ShadowBan(ctx context.Context, targetID, bannedByID string, options ...BanOption) (*Response, error) {
79+
options = append(options, banWithShadow(), banFromChannel(ch.Type, ch.ID))
80+
return ch.client.ShadowBan(ctx, targetID, bannedByID, options...)
81+
}
82+
83+
type QueryBannedUsersOptions struct {
84+
*QueryOption
85+
}
86+
87+
type QueryBannedUsersResponse struct {
88+
Bans []*Ban `json:"bans"`
89+
Response
90+
}
91+
92+
type Ban struct {
93+
Channel *Channel `json:"channel,omitempty"`
94+
User *User `json:"user"`
95+
Expires *time.Time `json:"expires,omitempty"`
96+
Reason string `json:"reason,omitempty"`
97+
Shadow bool `json:"shadow,omitempty"`
98+
BannedBy *User `json:"banned_by,omitempty"`
99+
CreatedAt time.Time `json:"created_at"`
100+
}
101+
102+
func (c *Client) QueryBannedUsers(ctx context.Context, q *QueryBannedUsersOptions, sorters ...*SortOption) (*QueryBannedUsersResponse, error) {
103+
qp := queryRequest{
104+
FilterConditions: q.Filter,
105+
Limit: q.Limit,
106+
Offset: q.Offset,
107+
Sort: sorters,
108+
}
109+
110+
data, err := json.Marshal(&qp)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
values := make(url.Values)
116+
values.Set("payload", string(data))
117+
118+
var resp QueryBannedUsersResponse
119+
err = c.makeRequest(ctx, http.MethodGet, "query_banned_users", values, nil, &resp)
120+
return &resp, err
121+
}
122+
123+
type banOptions struct {
124+
Reason string `json:"reason,omitempty"`
125+
Expiration int `json:"timeout,omitempty"`
126+
127+
TargetUserID string `json:"target_user_id"`
128+
BannedBy string `json:"user_id"`
129+
Shadow bool `json:"shadow"`
130+
131+
// ID and Type of the channel when acting on a channel member.
132+
ID string `json:"id"`
133+
Type string `json:"type"`
134+
}
135+
136+
type BanOption func(*banOptions)
137+
138+
func BanWithReason(reason string) func(*banOptions) {
139+
return func(opt *banOptions) {
140+
opt.Reason = reason
141+
}
142+
}
143+
144+
// BanWithExpiration set when the ban will expire. Should be in minutes.
145+
// eg. to ban during one hour: BanWithExpiration(60).
146+
func BanWithExpiration(expiration int) func(*banOptions) {
147+
return func(opt *banOptions) {
148+
opt.Expiration = expiration
149+
}
150+
}
151+
152+
func banWithShadow() func(*banOptions) {
153+
return func(opt *banOptions) {
154+
opt.Shadow = true
155+
}
156+
}
157+
158+
func banFromChannel(_type, id string) func(*banOptions) {
159+
return func(opt *banOptions) {
160+
opt.Type = _type
161+
opt.ID = id
162+
}
163+
}

ban_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package stream_chat
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestShadowBanUser(t *testing.T) {
11+
c := initClient(t)
12+
userA := randomUser(t, c)
13+
userB := randomUser(t, c)
14+
userC := randomUser(t, c)
15+
16+
ch := initChannel(t, c, userA.ID, userB.ID, userC.ID)
17+
resp, err := c.CreateChannel(context.Background(), ch.Type, ch.ID, userA.ID, nil)
18+
require.NoError(t, err)
19+
20+
ch = resp.Channel
21+
22+
// shadow ban userB globally
23+
_, err = c.ShadowBan(context.Background(), userB.ID, userA.ID)
24+
require.NoError(t, err)
25+
26+
// shadow ban userC on channel
27+
_, err = ch.ShadowBan(context.Background(), userC.ID, userA.ID)
28+
require.NoError(t, err)
29+
30+
msg := &Message{Text: "test message"}
31+
messageResp, err := ch.SendMessage(context.Background(), msg, userB.ID)
32+
require.NoError(t, err)
33+
34+
msg = messageResp.Message
35+
require.Equal(t, false, msg.Shadowed)
36+
37+
messageResp, err = c.GetMessage(context.Background(), msg.ID)
38+
require.NoError(t, err)
39+
require.Equal(t, true, messageResp.Message.Shadowed)
40+
41+
msg = &Message{Text: "test message"}
42+
messageResp, err = ch.SendMessage(context.Background(), msg, userC.ID)
43+
require.NoError(t, err)
44+
45+
msg = messageResp.Message
46+
require.Equal(t, false, msg.Shadowed)
47+
48+
messageResp, err = c.GetMessage(context.Background(), msg.ID)
49+
require.NoError(t, err)
50+
require.Equal(t, true, messageResp.Message.Shadowed)
51+
52+
_, err = c.UnBanUser(context.Background(), userB.ID)
53+
require.NoError(t, err)
54+
55+
msg = &Message{Text: "test message"}
56+
messageResp, err = ch.SendMessage(context.Background(), msg, userB.ID)
57+
require.NoError(t, err)
58+
59+
msg = messageResp.Message
60+
require.Equal(t, false, msg.Shadowed)
61+
62+
messageResp, err = c.GetMessage(context.Background(), msg.ID)
63+
require.NoError(t, err)
64+
require.Equal(t, false, messageResp.Message.Shadowed)
65+
66+
_, err = ch.UnBanUser(context.Background(), userC.ID)
67+
require.NoError(t, err)
68+
69+
msg = &Message{Text: "test message"}
70+
messageResp, err = ch.SendMessage(context.Background(), msg, userC.ID)
71+
require.NoError(t, err)
72+
73+
msg = messageResp.Message
74+
require.Equal(t, false, msg.Shadowed)
75+
76+
messageResp, err = c.GetMessage(context.Background(), msg.ID)
77+
require.NoError(t, err)
78+
require.Equal(t, false, messageResp.Message.Shadowed)
79+
}
80+
81+
func TestBanUnbanUser(t *testing.T) {
82+
c := initClient(t)
83+
target := randomUser(t, c)
84+
user := randomUser(t, c)
85+
86+
_, err := c.BanUser(context.Background(), target.ID, user.ID, BanWithReason("spammer"), BanWithExpiration(60))
87+
require.NoError(t, err)
88+
89+
resp, err := c.QueryBannedUsers(context.Background(), &QueryBannedUsersOptions{
90+
QueryOption: &QueryOption{Filter: map[string]interface{}{
91+
"user_id": map[string]string{"$eq": target.ID},
92+
}},
93+
})
94+
require.NoError(t, err)
95+
require.Equal(t, resp.Bans[0].Reason, "spammer")
96+
require.NotZero(t, resp.Bans[0].Expires)
97+
98+
_, err = c.UnBanUser(context.Background(), target.ID)
99+
require.NoError(t, err)
100+
101+
resp, err = c.QueryBannedUsers(context.Background(), &QueryBannedUsersOptions{
102+
QueryOption: &QueryOption{Filter: map[string]interface{}{
103+
"user_id": map[string]string{"$eq": target.ID},
104+
}},
105+
})
106+
require.NoError(t, err)
107+
require.Empty(t, resp.Bans)
108+
}
109+
110+
func TestChannelBanUnban(t *testing.T) {
111+
c := initClient(t)
112+
target := randomUser(t, c)
113+
user := randomUser(t, c)
114+
115+
ch := initChannel(t, c, user.ID, target.ID)
116+
117+
_, err := ch.BanUser(context.Background(), target.ID, user.ID, BanWithReason("spammer"), BanWithExpiration(60))
118+
require.NoError(t, err)
119+
120+
_, err = ch.UnBanUser(context.Background(), target.ID)
121+
require.NoError(t, err)
122+
123+
resp, err := c.QueryBannedUsers(context.Background(), &QueryBannedUsersOptions{
124+
QueryOption: &QueryOption{Filter: map[string]interface{}{
125+
"channel_cid": map[string]string{"$eq": ch.CID},
126+
}},
127+
})
128+
require.NoError(t, err)
129+
require.Empty(t, resp.Bans)
130+
}
131+
132+
func ExampleClient_BanUser() {
133+
client, _ := NewClient("XXXX", "XXXX")
134+
135+
// ban a user for 60 minutes from all channel
136+
_, _ = client.BanUser(context.Background(), "eviluser", "modUser", BanWithExpiration(60), BanWithReason("Banned for one hour"))
137+
138+
// ban a user from the livestream:fortnite channel
139+
channel := client.Channel("livestream", "fortnite")
140+
_, _ = channel.BanUser(context.Background(), "eviluser", "modUser", BanWithReason("Profanity is not allowed here"))
141+
142+
// remove ban from channel
143+
channel = client.Channel("livestream", "fortnite")
144+
_, _ = channel.UnBanUser(context.Background(), "eviluser")
145+
146+
// remove global ban
147+
_, _ = client.UnBanUser(context.Background(), "eviluser")
148+
}

0 commit comments

Comments
 (0)