1
0
mirror of synced 2024-11-25 06:26:03 +03:00

more fields for templates

This commit is contained in:
Pavel 2023-10-25 19:07:05 +03:00
parent 9f3cda8be6
commit 55d16c4dff
6 changed files with 350 additions and 74 deletions

View File

@ -153,15 +153,15 @@ func (c *MgClient) ActivateTemplate(channelID uint64, request ActivateTemplateRe
// if err != nil {
// fmt.Printf("%#v", err)
// }
func (c *MgClient) UpdateTemplate(request Template) (int, error) {
func (c *MgClient) UpdateTemplate(channelID uint64, code string, request UpdateTemplateRequest) (int, error) {
outgoing, _ := json.Marshal(&request)
if request.ChannelID == 0 || request.Code == "" {
if channelID == 0 || code == "" {
return 0, errors.New("`ChannelID` and `Code` cannot be blank")
}
data, status, err := c.PutRequest(
fmt.Sprintf("/channels/%d/templates/%s", request.ChannelID, url.PathEscape(request.Code)), outgoing)
fmt.Sprintf("/channels/%d/templates/%s", channelID, url.PathEscape(code)), outgoing)
if err != nil {
return status, err
}

View File

@ -351,24 +351,26 @@ func (t *MGClientTest) Test_ActivateTemplate() {
c := t.client()
req := ActivateTemplateRequest{
Code: "tplCode",
Name: "tplCode",
Type: TemplateTypeText,
Template: []TemplateItem{
{
Type: TemplateItemTypeText,
Text: "Hello ",
},
{
Type: TemplateItemTypeVar,
VarType: TemplateVarFirstName,
},
{
Type: TemplateItemTypeText,
Text: "!",
UpdateTemplateRequest: UpdateTemplateRequest{
Name: "tplCode",
Template: []TemplateItem{
{
Type: TemplateItemTypeText,
Text: "Hello ",
},
{
Type: TemplateItemTypeVar,
VarType: TemplateVarFirstName,
},
{
Type: TemplateItemTypeText,
Text: "!",
},
},
RejectionReason: "",
VerificationStatus: TemplateStatusApproved,
},
RejectionReason: "",
VerificationStatus: "approved",
}
defer gock.Off()
@ -384,12 +386,8 @@ func (t *MGClientTest) Test_ActivateTemplate() {
func (t *MGClientTest) Test_UpdateTemplate() {
c := t.client()
tpl := Template{
Code: "encodable#code",
ChannelID: 1,
Name: "updated name",
Enabled: true,
Type: TemplateTypeText,
tpl := UpdateTemplateRequest{
Name: "updated name",
Template: []TemplateItem{
{
Type: TemplateItemTypeText,
@ -421,16 +419,20 @@ func (t *MGClientTest) Test_UpdateTemplate() {
t.gock().
Get(t.transportURL("templates")).
Reply(http.StatusOK).
JSON([]Template{tpl})
JSON([]ActivateTemplateRequest{ActivateTemplateRequest{
UpdateTemplateRequest: tpl,
Code: "encodable#code",
Type: TemplateTypeText,
}})
status, err := c.UpdateTemplate(tpl)
status, err := c.UpdateTemplate(1, "encodable#code", tpl)
t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
templates, status, err := c.TransportTemplates()
t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
for _, template := range templates {
if template.Code == tpl.Code {
if template.Code == "encodable#code" {
t.Assert().Equal(tpl.Name, template.Name)
}
}
@ -438,10 +440,8 @@ func (t *MGClientTest) Test_UpdateTemplate() {
func (t *MGClientTest) Test_UpdateTemplateFail() {
c := t.client()
tpl := Template{
Name: "updated name",
Enabled: true,
Type: TemplateTypeText,
tpl := UpdateTemplateRequest{
Name: "updated name",
Template: []TemplateItem{
{
Type: TemplateItemTypeText,
@ -467,7 +467,7 @@ func (t *MGClientTest) Test_UpdateTemplateFail() {
},
)
status, err := c.UpdateTemplate(tpl)
status, err := c.UpdateTemplate(1, "encodable#code", tpl)
t.Assert().Error(err, fmt.Sprintf("%d %s", status, err))
}

View File

@ -1,14 +1,12 @@
package v1
import (
"bytes"
"encoding/json"
"errors"
"fmt"
)
// TemplateTypeText is a text template type. There is no other types for now.
const TemplateTypeText = "text"
const (
// TemplateItemTypeText is a type for text chunk in template.
TemplateItemTypeText uint8 = iota
@ -37,19 +35,232 @@ var templateVarAssoc = map[string]interface{}{
// Template struct.
type Template struct {
Code string `json:"code"`
ChannelID uint64 `json:"channel_id,omitempty"`
Name string `json:"name"`
Enabled bool `json:"enabled,omitempty"`
Type string `json:"type"`
Template []TemplateItem `json:"template"`
HeaderParams *HeaderParams `json:"headerParams,omitempty"`
Footer *string `json:"footer,omitempty"`
ButtonParams []ButtonParam `json:"buttonParams,omitempty"`
Lang string `json:"lang,omitempty"`
Category string `json:"category,omitempty"`
RejectionReason string `json:"rejection_reason,omitempty"`
VerificationStatus string `json:"verification_status,omitempty"`
ID int64 `json:"id,omitempty"`
Code string `json:"code,omitempty"`
ChannelID uint64 `json:"channel_id"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Type TemplateType `json:"type"`
Template []TemplateItem `json:"template"`
Body string `json:"body"`
Lang string `json:"lang,omitempty"`
Category string `json:"category,omitempty"`
Example *TemplateExample `json:"example,omitempty"`
VerificationStatus TemplateVerificationStatus `json:"verification_status"`
RejectionReason TemplateRejectionReason `json:"rejection_reason,omitempty"`
Header *TemplateHeader `json:"header,omitempty"`
Footer string `json:"footer,omitempty"`
Buttons *TemplateButtons `json:"buttons,omitempty"`
}
type TemplateExample struct {
Body []string `json:"body,omitempty"`
Header []string `json:"header,omitempty"`
Buttons [][]string `json:"buttons,omitempty"`
}
type TemplateButtons struct {
Items []Button `json:"items"`
}
func (b *TemplateButtons) UnmarshalJSON(value []byte) error {
var ScanType struct {
Items []json.RawMessage `json:"items"`
}
if err := json.Unmarshal(value, &ScanType); err != nil {
return err
}
var ButtonType struct {
Type ButtonType `json:"type"`
}
for _, r := range ScanType.Items {
if err := json.Unmarshal(r, &ButtonType); err != nil {
return err
}
var btn Button
switch ButtonType.Type {
case ButtonTypePlain:
btn = &PlainButton{}
case ButtonTypePhone:
btn = &PhoneButton{}
case ButtonTypeUrl:
btn = &UrlButton{}
default:
return errors.New("undefined type of button")
}
if err := json.Unmarshal(r, btn); err != nil {
return err
}
b.Items = append(b.Items, btn)
}
return nil
}
func (b TemplateButtons) MarshalJSON() ([]byte, error) {
var ValueType struct {
Items []json.RawMessage `json:"items"`
}
for _, btn := range b.Items {
btnData, err := json.Marshal(btn)
if err != nil {
return nil, err
}
buffer := bytes.NewBuffer(btnData[:len(btnData)-1])
buffer.WriteByte(',')
buffer.WriteString(fmt.Sprintf(`"type":"%s"`, btn.ButtonType()))
buffer.WriteByte('}')
ValueType.Items = append(ValueType.Items, buffer.Bytes())
}
d, err := json.Marshal(ValueType)
if err != nil {
return nil, err
}
return d, nil
}
type Button interface {
ButtonType() ButtonType
}
type ButtonType string
const (
ButtonTypePlain ButtonType = "plain"
ButtonTypePhone ButtonType = "phone"
ButtonTypeUrl ButtonType = "url"
)
type PlainButton struct {
Label string `json:"label"`
}
func (PlainButton) ButtonType() ButtonType { return ButtonTypePlain }
type PhoneButton struct {
Label string `json:"label"`
Phone string `json:"phone"`
}
func (PhoneButton) ButtonType() ButtonType { return ButtonTypePhone }
type UrlButton struct {
Label string `json:"label"`
Url string `json:"url"`
}
func (UrlButton) ButtonType() ButtonType { return ButtonTypeUrl }
type HeaderContent interface {
HeaderContentType() HeaderContentType
}
type HeaderContentType string
const (
HeaderContentTypeText HeaderContentType = "text"
HeaderContentTypeDocument HeaderContentType = "document"
HeaderContentTypeImage HeaderContentType = "image"
HeaderContentTypeVideo HeaderContentType = "video"
)
type HeaderContentText struct {
Body string `json:"body"`
}
func (HeaderContentText) HeaderContentType() HeaderContentType { return HeaderContentTypeText }
type HeaderContentDocument struct{}
func (HeaderContentDocument) HeaderContentType() HeaderContentType { return HeaderContentTypeDocument }
type HeaderContentImage struct{}
func (HeaderContentImage) HeaderContentType() HeaderContentType { return HeaderContentTypeImage }
type HeaderContentVideo struct{}
func (HeaderContentVideo) HeaderContentType() HeaderContentType { return HeaderContentTypeVideo }
type TemplateHeader struct {
Content HeaderContent `json:"content"`
}
func (h *TemplateHeader) UnmarshalJSON(value []byte) error {
var ScanType struct {
Content json.RawMessage `json:"content"`
}
if err := json.Unmarshal(value, &ScanType); err != nil {
return err
}
var ContentType struct {
Type HeaderContentType `json:"type"`
}
if err := json.Unmarshal(ScanType.Content, &ContentType); err != nil {
return err
}
var c HeaderContent
switch ContentType.Type {
case HeaderContentTypeText:
c = &HeaderContentText{}
case HeaderContentTypeDocument:
c = &HeaderContentDocument{}
case HeaderContentTypeImage:
c = &HeaderContentImage{}
case HeaderContentTypeVideo:
c = &HeaderContentVideo{}
default:
return errors.New("undefined type of header content")
}
if err := json.Unmarshal(ScanType.Content, c); err != nil {
return err
}
h.Content = c
return nil
}
func (h TemplateHeader) MarshalJSON() ([]byte, error) {
content, err := json.Marshal(h.Content)
if err != nil {
return nil, err
}
buffer := bytes.NewBuffer(content[:len(content)-1])
if buffer.Len() > 1 {
buffer.WriteByte(',')
}
buffer.WriteString(fmt.Sprintf(`"type":"%s"`, h.Content.HeaderContentType()))
buffer.WriteByte('}')
var ValueType struct {
Content json.RawMessage `json:"content"`
}
ValueType.Content = buffer.Bytes()
d, err := json.Marshal(ValueType)
if err != nil {
return nil, err
}
return d, nil
}
// TemplateItem is a part of template.

View File

@ -95,15 +95,15 @@ func TestUnmarshalMediaInteractiveTemplate(t *testing.T) {
assert.NoError(t, json.Unmarshal([]byte(input), &template))
assert.Equal(t, "aaa#bbb#ru", template.Code)
assert.Equal(t, []string{"Johny", "1234C"}, template.HeaderParams.TextVars)
assert.Equal(t, []string{"Johny", "1234C"}, template.Header.Content.TextVars)
assert.Equal(t, "http://example.com/intaro/d2354125", template.HeaderParams.ImageURL)
assert.Equal(t, "http://example.com/intaro/d2222", template.HeaderParams.VideoURL)
assert.Equal(t, "http://example.com/intaro/d4444", template.HeaderParams.DocumentURL)
assert.Equal(t, "Scooter", *template.Footer)
assert.Equal(t, "approved", template.VerificationStatus)
assert.Equal(t, URLButton, template.ButtonParams[0].ButtonType)
assert.Equal(t, "URL", template.ButtonParams[0].ButtonType)
assert.Equal(t, "222ddd", template.ButtonParams[0].URLParameter)
assert.Equal(t, QuickReplyButton, template.ButtonParams[1].ButtonType)
assert.Equal(t, "QUICK_REPLY", template.ButtonParams[1].ButtonType)
assert.Equal(t, "Yes", template.ButtonParams[1].Text)
input = `{"footer": "Scooter"}`

53
v1/template_type.go Normal file
View File

@ -0,0 +1,53 @@
package v1
import (
"bytes"
"errors"
)
type TemplateType uint8
const (
TemplateTypeText TemplateType = iota + 1
TemplateTypeMedia
)
var TypeMap = [][]byte{
TemplateTypeText: []byte("text"),
TemplateTypeMedia: []byte("media"),
}
var UnknownTypeValue = errors.New("unknown TemplateType")
func (e TemplateType) MarshalText() (text []byte, err error) {
if e.isValid() {
return TypeMap[e], nil
}
return nil, UnknownTypeValue
}
func (e TemplateType) String() string {
if e.isValid() {
return string(TypeMap[e])
}
panic(UnknownTypeValue)
}
func (e *TemplateType) UnmarshalText(text []byte) error {
for f, v := range TypeMap {
if !bytes.Equal(text, v) {
continue
}
*e = TemplateType(f)
return nil
}
return UnknownTypeValue
}
func (e TemplateType) isValid() bool {
return int(e) < len(TypeMap)
}

View File

@ -557,15 +557,25 @@ type TransportRequestMeta struct {
Timestamp int64 `json:"timestamp"`
}
type UpdateTemplateRequest struct {
Name string `json:"name"`
Template []TemplateItem `json:"template,omitempty"`
Body string `json:"body"`
Lang string `json:"lang,omitempty"`
Category string `json:"category,omitempty"`
Example *TemplateExample `json:"example,omitempty"`
VerificationStatus TemplateVerificationStatus `json:"verification_status"`
RejectionReason TemplateRejectionReason `json:"rejection_reason,omitempty"`
Header *TemplateHeader `json:"header,omitempty"`
Footer string `json:"footer,omitempty"`
Buttons *TemplateButtons `json:"buttons,omitempty"`
}
type ActivateTemplateRequest struct {
Code string `binding:"required,min=1,max=512" json:"code"`
Name string `binding:"required,min=1,max=512" json:"name"`
Type string `binding:"required" json:"type"`
Template []TemplateItem `json:"template"`
Lang string `json:"lang,omitempty"`
Category string `json:"category,omitempty"`
RejectionReason string `json:"rejection_reason,omitempty"`
VerificationStatus string `json:"verification_status,omitempty"`
UpdateTemplateRequest
Code string `json:"code"`
Type TemplateType `json:"type"`
}
var ErrInvalidOriginator = errors.New("invalid originator")
@ -646,14 +656,6 @@ type HeaderParams struct {
DocumentURL string `json:"documentUrl,omitempty"`
}
const (
QuickReplyButton ButtonType = "QUICK_REPLY"
PhoneNumberButton ButtonType = "PHONE_NUMBER"
URLButton ButtonType = "URL"
)
type ButtonType string
type ButtonParam struct {
ButtonType ButtonType `json:"type"`
Text string `json:"text,omitempty"`
@ -661,13 +663,14 @@ type ButtonParam struct {
}
type TemplateContent struct {
Name string `json:"name"`
Lang string `json:"lang"`
Category string `json:"category"`
Body string `json:"body"`
Example struct {
Body []string `json:"body"`
} `json:"example"`
Name string `json:"name"`
Lang string `json:"lang"`
Category string `json:"category"`
Body string `json:"body"`
Header *TemplateHeader `json:"header,omitempty"`
Footer string `json:"footer,omitempty"`
Buttons *TemplateButtons `json:"buttons,omitempty"`
Example *TemplateExample `json:"example,omitempty"`
}
type TemplateCreateWebhookData struct {
@ -700,3 +703,12 @@ const (
TemplateStatusRejected TemplateVerificationStatus = "rejected"
TemplateStatusNew TemplateVerificationStatus = "new"
)
type TemplateRejectionReason string
const (
ReasonAbusiveContent TemplateRejectionReason = "abusive_content"
ReasonIncorrectCategory TemplateRejectionReason = "incorrect_category"
ReasonInvalidFormat TemplateRejectionReason = "invalid_format"
ReasonScam TemplateRejectionReason = "scam"
)