Skip to content

Commit

Permalink
Support narrowcast message API (#191)
Browse files Browse the repository at this point in the history
* upport narrowcast message API

- implments #190
TODO:
- narrowcast progress API

* fix filter.demographic

* Update comment

* rename fliter to selector

* remove comment

* add `RequestID` on BasicResponse

* seperate interfaces by design

* Operators for Recipient and Demographic Filter, respectively

* add example test
  • Loading branch information
clsung authored Feb 25, 2020
1 parent 2b175e6 commit ffbe5cb
Show file tree
Hide file tree
Showing 6 changed files with 634 additions and 1 deletion.
1 change: 1 addition & 0 deletions linebot/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
APIEndpointBroadcastMessage = "/v2/bot/message/broadcast"
APIEndpointReplyMessage = "/v2/bot/message/reply"
APIEndpointMulticast = "/v2/bot/message/multicast"
APIEndpointNarrowcast = "/v2/bot/message/narrowcast"
APIEndpointGetMessageContent = "/v2/bot/message/%s/content"
APIEndpointGetMessageQuota = "/v2/bot/message/quota"
APIEndpointGetMessageConsumption = "/v2/bot/message/quota/consumption"
Expand Down
300 changes: 300 additions & 0 deletions linebot/demographic_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
// Copyright 2020 LINE Corporation
//
// LINE Corporation licenses this file to you under the Apache License,
// version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package linebot

import "encoding/json"

// DemographicFilter interface
type DemographicFilter interface {
DemographicFilter()
}

// GenderType type
type GenderType string

// GenderType constants
const (
GenderMale GenderType = "male"
GenderFemale GenderType = "female"
)

// GenderFilter type
type GenderFilter struct {
Type string `json:"type"`
Genders []GenderType `json:"oneOf"`
}

// NewGenderFilter function
func NewGenderFilter(genders ...GenderType) *GenderFilter {
return &GenderFilter{
Type: "gender",
Genders: genders,
}
}

// DemographicFilter implements DemographicFilter interface
func (*GenderFilter) DemographicFilter() {}

// AgeType type
type AgeType string

// AgeType constants
const (
AgeEmpty AgeType = ""
Age15 AgeType = "age_15"
Age20 AgeType = "age_20"
Age25 AgeType = "age_25"
Age30 AgeType = "age_30"
Age35 AgeType = "age_35"
Age40 AgeType = "age_40"
Age45 AgeType = "age_45"
Age50 AgeType = "age_50"
)

// AgeFilter type
type AgeFilter struct {
Type string `json:"type"`
GTE AgeType `json:"gte,omitempty"` // greater than or equal to
LT AgeType `json:"lt,omitempty"` // less than
}

// NewAgeFilter function
func NewAgeFilter(gte, lt AgeType) *AgeFilter {
return &AgeFilter{
Type: "age",
GTE: gte,
LT: lt,
}
}

// DemographicFilter implements DemographicFilter interface
func (*AgeFilter) DemographicFilter() {}

// AppType type
type AppType string

// AppType constants
const (
AppTypeIOS AppType = "ios"
AppTypeAndroid AppType = "android"
)

// AppTypeFilter type
type AppTypeFilter struct {
Type string `json:"type"`
AppTypes []AppType `json:"oneOf"`
}

// NewAppTypeFilter function
func NewAppTypeFilter(appTypes ...AppType) *AppTypeFilter {
return &AppTypeFilter{
Type: "appType",
AppTypes: appTypes,
}
}

// DemographicFilter implements DemographicFilter interface
func (*AppTypeFilter) DemographicFilter() {}

// AreaType type
type AreaType string

// AreaType constants
const (
AreaJPHokkaido AreaType = "jp_01"
AreaJPAomori AreaType = "jp_02"
AreaJPIwate AreaType = "jp_03"
AreaJPMiyagi AreaType = "jp_04"
AreaJPAkita AreaType = "jp_05"
AreaJPYamagata AreaType = "jp_06"
AreaJPFukushima AreaType = "jp_07"
AreaJPIbaraki AreaType = "jp_08"
AreaJPTochigi AreaType = "jp_09"
AreaJPGunma AreaType = "jp_10"
AreaJPSaitama AreaType = "jp_11"
AreaJPChiba AreaType = "jp_12"
AreaJPTokyo AreaType = "jp_13"
AreaJPKanagawa AreaType = "jp_14"
AreaJPNiigata AreaType = "jp_15"
AreaJPToyama AreaType = "jp_16"
AreaJPIshikawa AreaType = "jp_17"
AreaJPFukui AreaType = "jp_18"
AreaJPYamanashi AreaType = "jp_19"
AreaJPNagano AreaType = "jp_20"
AreaJPGifu AreaType = "jp_21"
AreaJPShizuoka AreaType = "jp_22"
AreaJPAichi AreaType = "jp_23"
AreaJPMie AreaType = "jp_24"
AreaJPShiga AreaType = "jp_25"
AreaJPKyoto AreaType = "jp_26"
AreaJPOsaka AreaType = "jp_27"
AreaJPHyougo AreaType = "jp_28"
AreaJPNara AreaType = "jp_29"
AreaJPWakayama AreaType = "jp_30"
AreaJPTottori AreaType = "jp_31"
AreaJPShimane AreaType = "jp_32"
AreaJPOkayama AreaType = "jp_33"
AreaJPHiroshima AreaType = "jp_34"
AreaJPYamaguchi AreaType = "jp_35"
AreaJPTokushima AreaType = "jp_36"
AreaJPKagawa AreaType = "jp_37"
AreaJPEhime AreaType = "jp_38"
AreaJPKouchi AreaType = "jp_39"
AreaJPFukuoka AreaType = "jp_40"
AreaJPSaga AreaType = "jp_41"
AreaJPNagasaki AreaType = "jp_42"
AreaJPKumamoto AreaType = "jp_43"
AreaJPOita AreaType = "jp_44"
AreaJPMiyazaki AreaType = "jp_45"
AreaJPKagoshima AreaType = "jp_46"
AreaJPOkinawa AreaType = "jp_47"
AreaTWTaipeiCity AreaType = "tw_01"
AreaTWNewTaipeiCity AreaType = "tw_02"
AreaTWTaoyuanCity AreaType = "tw_03"
AreaTWTaichungCity AreaType = "tw_04"
AreaTWTainanCity AreaType = "tw_05"
AreaTWKaohsiungCity AreaType = "tw_06"
AreaTWKeelungCity AreaType = "tw_07"
AreaTWHsinchuCity AreaType = "tw_08"
AreaTWChiayiCity AreaType = "tw_09"
AreaTWHsinchuCounty AreaType = "tw_10"
AreaTWMiaoliCounty AreaType = "tw_11"
AreaTWChanghuaCounty AreaType = "tw_12"
AreaTWNantouCounty AreaType = "tw_13"
AreaTWYunlinCounty AreaType = "tw_14"
AreaTWChiayiCounty AreaType = "tw_15"
AreaTWPingtungCounty AreaType = "tw_16"
AreaTWYilanCounty AreaType = "tw_17"
AreaTWHualienCounty AreaType = "tw_18"
AreaTWTaitungCounty AreaType = "tw_19"
AreaTWPenghuCounty AreaType = "tw_20"
AreaTWKinmenCounty AreaType = "tw_21"
AreaTWLienchiangCounty AreaType = "tw_22"
AreaTHBangkok AreaType = "th_01"
AreaTHPattaya AreaType = "th_02"
AreaTHNorthern AreaType = "th_03"
AreaTHCentral AreaType = "th_04"
AreaTHSouthern AreaType = "th_05"
AreaTHEastern AreaType = "th_06"
AreaTHNorthEastern AreaType = "th_07"
AreaTHWestern AreaType = "th_08"
AreaIDBali AreaType = "id_01"
AreaIDBandung AreaType = "id_02"
AreaIDBanjarmasin AreaType = "id_03"
AreaIDJabodetabek AreaType = "id_04"
AreaIDLainnya AreaType = "id_05"
AreaIDMakassar AreaType = "id_06"
AreaIDMedan AreaType = "id_07"
AreaIDPalembang AreaType = "id_08"
AreaIDSamarinda AreaType = "id_09"
AreaIDSemarang AreaType = "id_10"
AreaIDSurabaya AreaType = "id_11"
AreaIDYogyakarta AreaType = "id_12"
)

// AreaFilter type
type AreaFilter struct {
Type string `json:"type"`
Areas []AreaType `json:"oneOf"`
}

// NewAreaFilter function
func NewAreaFilter(areaTypes ...AreaType) *AreaFilter {
return &AreaFilter{
Type: "area",
Areas: areaTypes,
}
}

// DemographicFilter implements DemographicFilter interface
func (*AreaFilter) DemographicFilter() {}

// PeriodType type
type PeriodType string

// PeriodType constants
const (
PeriodEmpty PeriodType = ""
PeriodDay7 PeriodType = "day_7"
PeriodDay30 PeriodType = "day_30"
PeriodDay90 PeriodType = "day_90"
PeriodDay180 PeriodType = "day_180"
PeriodDay365 PeriodType = "day_365"
)

// SubscriptionPeriodFilter type
type SubscriptionPeriodFilter struct {
Type string `json:"type"`
GTE PeriodType `json:"gte,omitempty"` // greater than or equal to
LT PeriodType `json:"lt,omitempty"` // less than
}

// NewSubscriptionPeriodFilter function
func NewSubscriptionPeriodFilter(gte, lt PeriodType) *SubscriptionPeriodFilter {
return &SubscriptionPeriodFilter{
Type: "subscriptionPeriod",
GTE: gte,
LT: lt,
}
}

// DemographicFilter implements DemographicFilter interface
func (*SubscriptionPeriodFilter) DemographicFilter() {}

// DemographicFilterOperator struct
type DemographicFilterOperator struct {
ConditionAnd []DemographicFilter `json:"and,omitempty"`
ConditionOr []DemographicFilter `json:"or,omitempty"`
ConditionNot DemographicFilter `json:"not,omitempty"`
}

// DemographicFilterOperatorAnd method
func DemographicFilterOperatorAnd(conditions ...DemographicFilter) *DemographicFilterOperator {
return &DemographicFilterOperator{
ConditionAnd: conditions,
}
}

// DemographicFilterOperatorOr method
func DemographicFilterOperatorOr(conditions ...DemographicFilter) *DemographicFilterOperator {
return &DemographicFilterOperator{
ConditionOr: conditions,
}
}

// DemographicFilterOperatorNot method
func DemographicFilterOperatorNot(condition DemographicFilter) *DemographicFilterOperator {
return &DemographicFilterOperator{
ConditionNot: condition,
}
}

// MarshalJSON method of DemographicFilterOperator
func (o *DemographicFilterOperator) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Type string `json:"type"`
ConditionAnd []DemographicFilter `json:"and,omitempty"`
ConditionOr []DemographicFilter `json:"or,omitempty"`
ConditionNot DemographicFilter `json:"not,omitempty"`
}{
Type: "operator",
ConditionAnd: o.ConditionAnd,
ConditionOr: o.ConditionOr,
ConditionNot: o.ConditionNot,
})
}

// DemographicFilter implements DemographicFilter interface
func (*DemographicFilterOperator) DemographicFilter() {}
85 changes: 85 additions & 0 deletions linebot/recipient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2020 LINE Corporation
//
// LINE Corporation licenses this file to you under the Apache License,
// version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package linebot

import "encoding/json"

// Recipient interface
type Recipient interface {
Recipient()
}

// AudienceObject type is created to be used with specific recipient objects
type AudienceObject struct {
Type string `json:"type"`
GroupID int `json:"audienceGroupId"`
}

// NewAudienceObject function
func NewAudienceObject(groupID int) *AudienceObject {
return &AudienceObject{
Type: "audience",
GroupID: groupID,
}
}

// Recipient implements Recipient interface
func (*AudienceObject) Recipient() {}

// RecipientOperator struct
type RecipientOperator struct {
ConditionAnd []Recipient `json:"and,omitempty"`
ConditionOr []Recipient `json:"or,omitempty"`
ConditionNot Recipient `json:"not,omitempty"`
}

// RecipientOperatorAnd method
func RecipientOperatorAnd(conditions ...Recipient) *RecipientOperator {
return &RecipientOperator{
ConditionAnd: conditions,
}
}

// RecipientOperatorOr method
func RecipientOperatorOr(conditions ...Recipient) *RecipientOperator {
return &RecipientOperator{
ConditionOr: conditions,
}
}

// RecipientOperatorNot method
func RecipientOperatorNot(condition Recipient) *RecipientOperator {
return &RecipientOperator{
ConditionNot: condition,
}
}

// MarshalJSON method of Operator
func (o *RecipientOperator) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Type string `json:"type"`
ConditionAnd []Recipient `json:"and,omitempty"`
ConditionOr []Recipient `json:"or,omitempty"`
ConditionNot Recipient `json:"not,omitempty"`
}{
Type: "operator",
ConditionAnd: o.ConditionAnd,
ConditionOr: o.ConditionOr,
ConditionNot: o.ConditionNot,
})
}

// Recipient implements Recipient interface
func (*RecipientOperator) Recipient() {}
Loading

0 comments on commit ffbe5cb

Please sign in to comment.