Skip to content

Commit 85ef9a1

Browse files
authored
feat: add flag to allow exclamation mark in channel ID (#151)
* feat: add flag to allow exlamation mark in channel ID
1 parent a7f2ea6 commit 85ef9a1

File tree

6 files changed

+114
-13
lines changed

6 files changed

+114
-13
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @ferhatelmas @gumuz @yaziine
1+
* @gumuz @yaziine

pkg/cmd/chat/imports/imports.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,28 @@ func NewCmds() []*cobra.Command {
2525
}
2626
}
2727

28-
func validateFile(ctx context.Context, c *stream.Client, filename string) (*validator.Results, error) {
28+
func validateFile(cmd *cobra.Command, c *stream.Client, filename string) (*validator.Results, error) {
2929
reader, err := os.Open(filename)
3030
if err != nil {
3131
return nil, err
3232
}
3333
defer reader.Close()
3434

35-
rolesResp, err := c.Permissions().ListRoles(ctx)
35+
rolesResp, err := c.Permissions().ListRoles(cmd.Context())
3636
if err != nil {
3737
return nil, err
3838
}
3939

40-
channelTypesResp, err := c.ListChannelTypes(ctx)
40+
channelTypesResp, err := c.ListChannelTypes(cmd.Context())
4141
if err != nil {
4242
return nil, err
4343
}
4444

45-
return validator.New(reader, rolesResp.Roles, channelTypesResp.ChannelTypes).Validate(), nil
45+
var options []validator.Options
46+
if light, _ := cmd.Flags().GetBool("lighter-validation-id"); light {
47+
options = append(options, validator.LighterValidationChannelID())
48+
}
49+
return validator.New(reader, rolesResp.Roles, channelTypesResp.ChannelTypes, options...).Validate(), nil
4650
}
4751

4852
func validateCmd() *cobra.Command {
@@ -60,7 +64,7 @@ func validateCmd() *cobra.Command {
6064
return err
6165
}
6266

63-
results, err := validateFile(cmd.Context(), c, args[0])
67+
results, err := validateFile(cmd, c, args[0])
6468
if err != nil {
6569
return err
6670
}
@@ -71,6 +75,7 @@ func validateCmd() *cobra.Command {
7175

7276
fl := cmd.Flags()
7377
fl.StringP("output-format", "o", "json", "[optional] Output format. Can be json or tree")
78+
fl.Bool("lighter-validation-id", false, "[optional] allows to pass ! in channel ID")
7479

7580
return cmd
7681
}
@@ -123,7 +128,7 @@ func uploadCmd() *cobra.Command {
123128

124129
filename := args[0]
125130

126-
results, err := validateFile(cmd.Context(), c, filename)
131+
results, err := validateFile(cmd, c, filename)
127132
if err != nil {
128133
return err
129134
}
@@ -156,6 +161,7 @@ func uploadCmd() *cobra.Command {
156161
fl := cmd.Flags()
157162
fl.StringP("mode", "m", "upsert", "[optional] Import mode. Canbe upsert or insert")
158163
fl.StringP("output-format", "o", "json", "[optional] Output format. Can be json or tree")
164+
fl.Bool("lighter-validation-id", false, "[optional] allows to pass ! in channel ID")
159165

160166
return cmd
161167
}

pkg/cmd/chat/imports/validator/items.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import (
1414
)
1515

1616
var (
17+
// validChannelIDRe regex differs if lighter-validation-id flag is given
18+
validChannelIDRe *regexp.Regexp
19+
1720
validUserIDRe = regexp.MustCompile(`^[@\w-]*$`)
18-
validChannelIDRe = regexp.MustCompile(`^[\w-]*$`)
1921
validReactionTypeRe = regexp.MustCompile(`^[\w-+:.]*$`)
2022
)
2123

@@ -278,7 +280,7 @@ func (c *channelItem) validateFields() error {
278280
}
279281

280282
if !validChannelIDRe.MatchString(c.ID) {
281-
return fmt.Errorf(`channel.id invalid ("%s" allowed)`, validChannelIDRe)
283+
return fmt.Errorf(`channel.id %q invalid ("%s" allowed)`, c.ID, validChannelIDRe)
282284
}
283285

284286
if c.Type == "" {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
[
2+
{
3+
"type": "user",
4+
"item": {
5+
"id": "user1",
6+
"role": "user"
7+
}
8+
},
9+
{
10+
"type": "user",
11+
"item": {
12+
"id": "user2",
13+
"role": "user"
14+
}
15+
},
16+
{
17+
"type": "channel",
18+
"item": {
19+
"id": "channelA",
20+
"type": "messaging",
21+
"created_by": "user1"
22+
}
23+
},
24+
{
25+
"type": "member",
26+
"item": {
27+
"channel_id": "channelA",
28+
"channel_type": "messaging",
29+
"user_id": "user1"
30+
}
31+
},
32+
{
33+
"type": "channel",
34+
"item": {
35+
"id": "!members-channelB",
36+
"type": "messaging",
37+
"created_by": "user2"
38+
}
39+
},
40+
{
41+
"type": "member",
42+
"item": {
43+
"channel_id": "!members-channelB",
44+
"channel_type": "messaging",
45+
"user_id": "user2"
46+
}
47+
},
48+
{
49+
"type": "message",
50+
"item": {
51+
"id": "message2",
52+
"channel_id": "!members-channelB",
53+
"channel_type": "messaging",
54+
"user": "user2",
55+
"text": "hi!"
56+
}
57+
}
58+
]

pkg/cmd/chat/imports/validator/validator.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package validator
22

33
import (
44
"io"
5+
"regexp"
56

67
streamchat "github.com/GetStream/stream-chat-go/v5"
78
)
@@ -22,17 +23,41 @@ func newResults(stats map[string]int, errs *multiError) *Results {
2223
}
2324
}
2425

26+
type Options func(*option)
27+
28+
type option struct {
29+
lighterValidationChannelID bool
30+
}
31+
32+
func LighterValidationChannelID() Options {
33+
return func(o *option) {
34+
o.lighterValidationChannelID = true
35+
}
36+
}
37+
2538
type Validator struct {
2639
decoder *Decoder
2740
index *index
2841
}
2942

30-
func New(r io.ReadSeeker, roles []*streamchat.Role, channelTypes channelTypeMap) *Validator {
43+
func New(r io.ReadSeeker, roles []*streamchat.Role, channelTypes channelTypeMap, options ...Options) *Validator {
3144
roleMap := make(roleMap, len(roles))
3245
for _, role := range roles {
3346
roleMap[role.Name] = role
3447
}
3548

49+
opt := &option{}
50+
for _, o := range options {
51+
o(opt)
52+
}
53+
54+
if opt.lighterValidationChannelID {
55+
// allows to pass ! in channel ID
56+
validChannelIDRe = regexp.MustCompile(`^[\w!-]*$`)
57+
} else {
58+
validChannelIDRe = regexp.MustCompile(`^[\w-]*$`)
59+
}
60+
3661
return &Validator{
3762
decoder: NewDecoder(r),
3863
index: newIndex(roleMap, channelTypes),

pkg/cmd/chat/imports/validator/validator_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ func TestValidator_Validate(t *testing.T) {
1515
name string
1616
filename string
1717
want *Results
18+
19+
lighterChanIDValidation bool
1820
}{
1921
{name: "Valid data", filename: "valid-data.json", want: &Results{
2022
Stats: map[string]int{"channels": 3, "devices": 2, "members": 4, "messages": 3, "reactions": 3, "users": 4},
2123
Errors: nil,
2224
}},
25+
{name: "Valid channels with lighter channel ID validation", filename: "valid-channels-with-light.json", lighterChanIDValidation: true, want: &Results{
26+
Stats: map[string]int{"channels": 2, "devices": 0, "members": 2, "messages": 1, "reactions": 0, "users": 2},
27+
Errors: nil,
28+
}},
2329
{name: "Invalid users", filename: "invalid-users.json", want: &Results{
2430
Stats: map[string]int{"channels": 0, "devices": 0, "members": 0, "messages": 0, "reactions": 0, "users": 1},
2531
Errors: []error{
@@ -38,7 +44,7 @@ func TestValidator_Validate(t *testing.T) {
3844
errors.New(`validation error: either channel.id or channel.member_ids required`),
3945
errors.New(`validation error: channel.id max length exceeded (64)`),
4046
errors.New(`validation error: channel.type required`),
41-
errors.New(`validation error: channel.id invalid ("^[\w-]*$" allowed)`),
47+
errors.New(`validation error: channel.id "channelA@abc" invalid ("^[\w-]*$" allowed)`),
4248
errors.New(`validation error: channel.created_by required`),
4349
errors.New(`validation error: channel.cid is a reserved field`),
4450
errors.New(`reference error: channel.type "" doesn't exist (channel ":channelA")`),
@@ -108,12 +114,16 @@ func TestValidator_Validate(t *testing.T) {
108114
require.NoError(t, err)
109115
defer f.Close()
110116

111-
v := New(f, []*stream.Role{{Name: "user"}}, map[string]*stream.ChannelType{"messaging": nil})
117+
var options []Options
118+
if tt.lighterChanIDValidation {
119+
options = append(options, LighterValidationChannelID())
120+
}
121+
v := New(f, []*stream.Role{{Name: "user"}}, map[string]*stream.ChannelType{"messaging": nil}, options...)
112122

113123
got := v.Validate()
114124

115125
require.Equal(t, tt.want.Stats, got.Stats)
116-
require.Equal(t, len(tt.want.Errors), len(got.Errors))
126+
require.Equal(t, len(tt.want.Errors), len(got.Errors), got.Errors)
117127
for i := range tt.want.Errors {
118128
require.Equal(t, tt.want.Errors[i].Error(), got.Errors[i].Error(), fmt.Sprintf(`errors #%d doesn't match`, i))
119129
}

0 commit comments

Comments
 (0)