Skip to content

Commit

Permalink
feat: add devices validation (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
yaziine authored Sep 22, 2022
1 parent 3f4e9a9 commit 4ab96e7
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 36 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: "1.18"
go-version: "1.19"

- uses: actions/checkout@v2

Expand All @@ -27,4 +27,4 @@ jobs:
STREAM_SECRET: ${{ secrets.STREAM_SECRET }}
run: |
go test -coverprofile cover.out -v -race ./...
go tool cover -func=cover.out
go tool cover -func=cover.out
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '1.18'
go-version: '1.19'

- name: Tidy
run: go mod tidy -v && git diff --no-patch --exit-code || { git status; echo 'Unchecked diff, did you forget go mod tidy again?' ; false ; };
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.18'
go-version: '1.19'

- run: |
git tag "${{ env.VERSION }}"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/reviewdog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: "1.18"
go-version: "1.19"

- name: Install golangci-lint
run:
Expand All @@ -30,4 +30,4 @@ jobs:
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run:
$(go env GOPATH)/bin/golangci-lint run --out-format line-number | reviewdog -f=golangci-lint -name=golangci-lint -reporter=github-pr-review
$(go env GOPATH)/bin/golangci-lint run --out-format line-number | reviewdog -f=golangci-lint -name=golangci-lint -reporter=github-pr-review
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
run:
go: '1.18'
go: '1.19'
deadline: 210s
timeout: 10m
skip-dirs:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
NAME = stream-cli

GOLANGCI_VERSION = 1.45.0
GOLANGCI_VERSION = 1.49.0
GOLANGCI = .bin/golangci/$(GOLANGCI_VERSION)/golangci-lint
$(GOLANGCI):
@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(dir $(GOLANGCI)) v$(GOLANGCI_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/GetStream/stream-cli

go 1.18
go 1.19

require (
github.com/AlecAivazis/survey/v2 v2.3.4
Expand Down
25 changes: 25 additions & 0 deletions pkg/cmd/chat/imports/validator/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ type index struct {

// reactions
reactionPKs map[Bits256]struct{}

// devices
devicePKs map[Bits256]struct{}
}

func newIndex(roles map[string]*streamchat.Role, channelTypes map[string]*streamchat.ChannelType) *index {
Expand All @@ -84,6 +87,7 @@ func newIndex(roles map[string]*streamchat.Role, channelTypes map[string]*stream
messagePKsWithReaction: make(map[Bits256]struct{}),
messagePKsReplies: make(map[Bits256]struct{}),
reactionPKs: make(map[Bits256]struct{}),
devicePKs: make(map[Bits256]struct{}),
}
}

Expand All @@ -94,6 +98,7 @@ func (i *index) stats() map[string]int {
"members": len(i.memberPKs),
"messages": len(i.messagePKs),
"reactions": len(i.reactionPKs),
"devices": len(i.devicePKs),
}
}

Expand Down Expand Up @@ -302,3 +307,23 @@ func (i *index) addReaction(messageID, reactionType, userID string) error {

return nil
}

func getDevicePK(deviceID string) Bits256 {
return hashValues(deviceID)
}

func (i *index) deviceExist(deviceID string) bool {
pk := getDevicePK(deviceID)
_, ok := i.devicePKs[pk]
return ok
}

func (i *index) addDevice(deviceID string) error {
if i.deviceExist(deviceID) {
return fmt.Errorf("duplicate device id:%s", deviceID)
}

pk := getDevicePK(deviceID)
i.devicePKs[pk] = struct{}{}
return nil
}
98 changes: 90 additions & 8 deletions pkg/cmd/chat/imports/validator/items.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"strings"
"time"
"unicode/utf8"

streamchat "github.com/GetStream/stream-chat-go/v5"
)

var (
Expand All @@ -35,6 +37,8 @@ func newItem(rawItem *rawItem) (Item, error) {
return newMessageItem(rawItem.Item)
case "reaction":
return newReactionItem(rawItem.Item)
case "device":
return newDeviceItem(rawItem.Item)
default:
return nil, fmt.Errorf("invalid item type %q", rawItem.Type)
}
Expand Down Expand Up @@ -88,14 +92,20 @@ func newUserItem(itemBody json.RawMessage) (*userItem, error) {
}

type userItem struct {
ID string `json:"id"`
Role string `json:"role"`
Invisible bool `json:"invisible"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt time.Time `json:"deleted_at"`
Teams []string `json:"teams"`
Custom extraFields
ID string `json:"id"`
Role string `json:"role"`
Invisible bool `json:"invisible"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt time.Time `json:"deleted_at"`
Teams []string `json:"teams"`
PushNotifications pushNotification `json:"push_notifications"`
Custom extraFields
}

type pushNotification struct {
Disabled bool `json:"disabled"`
DisabledUntil *time.Time `json:"disabled_until"`
}

func (u *userItem) validateFields() error {
Expand Down Expand Up @@ -130,6 +140,78 @@ func (u *userItem) validateReferences(idx *index) error {
return nil
}

type deviceItem struct {
ID string `json:"id"`
UserID string `json:"user_id"`
CreatedAt time.Time `json:"created_at"`
Disabled bool `json:"disabled"`
DisabledReason string `json:"disabled_reason"`
PushProviderType string `json:"push_provider_type"`
PushProviderName string `json:"push_provider_name"`
}

func newDeviceItem(itemBody json.RawMessage) (*deviceItem, error) {
var device deviceItem
if err := unmarshalItem(itemBody, &device); err != nil {
return nil, err
}
return &device, nil
}

var pushProviders = []string{
streamchat.PushProviderFirebase,
streamchat.PushProviderHuawei,
streamchat.PushProviderAPNS,
streamchat.PushProviderXiaomi,
}

func (d *deviceItem) validateFields() error {
if d.ID == "" {
return errors.New("device.id required")
}
if len(d.ID) > 255 {
return errors.New("device.id max length exceeded (255)")
}

if d.UserID == "" {
return errors.New("device.user_id required")
}
if len(d.UserID) > 255 {
return errors.New("device.user_id max length exceeded (255)")
}

if d.CreatedAt.IsZero() {
return errors.New("device.created_at required")
}

if d.PushProviderType == "" {
return errors.New("device.push_provider_type required")
}
var found bool
for _, p := range pushProviders {
if d.PushProviderType == p {
found = true
break
}
}
if !found {
return fmt.Errorf("device.push_provider_type invalid, available options are: %s", strings.Join(pushProviders, ","))
}

return nil
}

func (d *deviceItem) index(i *index) error {
return i.addDevice(d.ID)
}

func (d *deviceItem) validateReferences(i *index) error {
if d.UserID != "" && !i.userExist(d.UserID) {
return fmt.Errorf("device.user_id %q doesn't exist", d.UserID)
}
return nil
}

var channelReservedFields = []string{
"last_message_at", "cid", "created_by_pk", "members", "config", "app_pk", "pk",
}
Expand Down
86 changes: 86 additions & 0 deletions pkg/cmd/chat/imports/validator/testdata/invalid-devices.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[
{
"type": "user",
"item": {
"id": "userA",
"role": "user"
}
},
{
"type": "device",
"item": {
"id": "id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long-id-too-long",
"user_id": "userA",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "firebase"
}
},
{
"type": "device",
"item": {
"id": "123",
"user_id": "userB",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "firebase"
}
},
{
"type": "device",
"item": {
"user_id": "userA",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "firebase"
}
},
{
"type": "device",
"item": {
"id": "no user ID",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "firebase"
}
},
{
"type": "device",
"item": {
"id": "123",
"user_id": "userA",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "unknown_provider"
}
},
{
"type": "device",
"item": {
"id": "123",
"user_id": "userA",
"disabled": false,
"push_provider_type": "unknown_provider"
}
},
{
"type": "device",
"item": {
"id": "duplicate",
"user_id": "userA",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "apn"
}
},
{
"type": "device",
"item": {
"id": "duplicate",
"user_id": "userA",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "xiaomi"
}
}
]
32 changes: 30 additions & 2 deletions pkg/cmd/chat/imports/validator/testdata/valid-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
"teams": [
"teamA"
],
"foo": "bar"
"foo": "bar",
"push_notifications": {
"disabled": true,
"disabled_until": "2022-12-31T23:59:59Z"
}
}
},
{
Expand All @@ -17,7 +21,10 @@
"role": "user",
"teams": [
"teamB"
]
],
"push_notifications": {
"disabled": false
}
}
},
{
Expand Down Expand Up @@ -160,5 +167,26 @@
"user_id": "user3",
"created_at": "2022-01-01T01:01:01Z"
}
},
{
"type": "device",
"item": {
"id": "123",
"user_id": "user1",
"created_at": "2022-01-01T01:01:01Z",
"disabled": true,
"disabled_reason": "provider creds are not valid",
"push_provider_type": "xiaomi"
}
},
{
"type": "device",
"item": {
"id": "456",
"user_id": "user2",
"created_at": "2022-01-01T01:01:01Z",
"disabled": false,
"push_provider_type": "firebase"
}
}
]
Loading

0 comments on commit 4ab96e7

Please sign in to comment.