Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions models.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,96 @@ type Event struct {
Data map[string]any `json:"data"`
}

// Channel identifies the delivery channel for inbox messages.
type Channel string

// InboxStatus filters inbox messages by status.
type InboxStatus string

const (
InboxStatusUnread InboxStatus = "unread"
InboxStatusOpened InboxStatus = "opened"
InboxStatusArchived InboxStatus = "archived"
)

// UserInboxQuery holds filters for querying user inbox messages.
type UserInboxQuery struct {
Source string
ExternalID string
Status *InboxStatus
Tags []string
MessageSource *string
Priority *int
Channel Channel
Limit *int
Offset *int
}

// PostUserInboxMessagesRequest is the payload for creating user inbox messages.
type PostUserInboxMessagesRequest struct {
Source string `json:"source"`
ExternalID string `json:"external_id"`
Messages []map[string]any `json:"messages"`
}

// UserInboxMessageEvents is the payload for marking user inbox messages as opened or archived.
type UserInboxMessageEvents struct {
Source string `json:"source"`
ExternalID string `json:"external_id"`
MessageIDs []string `json:"message_ids"`
}

// InboxMessage is a single inbox message as returned by the API.
type InboxMessage struct {
ID string `json:"id"`
Data map[string]any `json:"data"`
Status InboxStatus `json:"status"`
Channel Channel `json:"channel"`
Priority int `json:"priority"`
Tags []string `json:"tags"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

// InboxMessageList is the response payload for inbox message queries.
type InboxMessageList struct {
Data []InboxMessage `json:"data"`
Total int `json:"total"`
}

// InboxCount is the response payload for inbox count queries.
type InboxCount struct {
Unread int `json:"unread"`
Total int `json:"total"`
}

// OrganizationInboxQuery holds filters for querying organization inbox messages.
type OrganizationInboxQuery struct {
Source string
ExternalID string
Status *InboxStatus
Tags []string
MessageSource *string
Priority *int
Channel Channel
Limit *int
Offset *int
}

// PostOrganizationInboxMessagesRequest is the payload for creating organization inbox messages.
type PostOrganizationInboxMessagesRequest struct {
Source string `json:"source"`
ExternalID string `json:"external_id"`
Messages []map[string]any `json:"messages"`
}

// OrganizationInboxMessageEvents is the payload for marking organization inbox messages as opened or archived.
type OrganizationInboxMessageEvents struct {
Source string `json:"source"`
ExternalID string `json:"external_id"`
MessageIDs []string `json:"message_ids"`
}

// UpsertOrganizationRequest creates or updates an organization.
type UpsertOrganizationRequest struct {
Identifier []ExternalID `json:"identifier"`
Expand Down
81 changes: 81 additions & 0 deletions organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package lunogram
import (
"context"
"net/http"
"net/url"
"strconv"
"strings"
)

// UpsertOrganization creates or updates an organization by external identifier(s).
Expand Down Expand Up @@ -36,3 +39,81 @@ func (c *Client) RemoveOrganizationUser(ctx context.Context, req *RemoveOrganiza
func (c *Client) PostOrganizationEvents(ctx context.Context, events []OrganizationEvent) error {
return c.do(ctx, http.MethodPost, "/api/client/organizations/events", events, nil)
}

// PostOrganizationInboxMessages creates one or more inbox messages for organizations.
func (c *Client) PostOrganizationInboxMessages(ctx context.Context, req *PostOrganizationInboxMessagesRequest) error {
return c.do(ctx, http.MethodPost, "/api/client/organizations/inbox", req, nil)
}

// GetOrganizationInbox retrieves visible, non-expired inbox messages for an organization.
func (c *Client) GetOrganizationInbox(ctx context.Context, query *OrganizationInboxQuery) (*InboxMessageList, error) {
path := "/api/client/organizations/inbox"
if values := organizationInboxQueryValues(query); len(values) > 0 {
path += "?" + values.Encode()
}

var list InboxMessageList
if err := c.do(ctx, http.MethodGet, path, nil, &list); err != nil {
return nil, err
}
return &list, nil
}

// GetOrganizationInboxCount retrieves unread and total inbox message counts for an organization.
func (c *Client) GetOrganizationInboxCount(ctx context.Context, query *OrganizationInboxQuery) (*InboxCount, error) {
path := "/api/client/organizations/inbox/count"
if values := organizationInboxQueryValues(query); len(values) > 0 {
path += "?" + values.Encode()
}

var count InboxCount
if err := c.do(ctx, http.MethodGet, path, nil, &count); err != nil {
return nil, err
}
return &count, nil
}

// PostOrganizationInboxOpened marks one or more organization inbox messages as opened.
func (c *Client) PostOrganizationInboxOpened(ctx context.Context, events *OrganizationInboxMessageEvents) error {
return c.do(ctx, http.MethodPost, "/api/client/organizations/inbox/opened", events, nil)
}

// PostOrganizationInboxArchived marks one or more organization inbox messages as archived.
func (c *Client) PostOrganizationInboxArchived(ctx context.Context, events *OrganizationInboxMessageEvents) error {
return c.do(ctx, http.MethodPost, "/api/client/organizations/inbox/archived", events, nil)
}

func organizationInboxQueryValues(query *OrganizationInboxQuery) url.Values {
values := url.Values{}
if query == nil {
return values
}
if query.Source != "" {
values.Set("source", query.Source)
}
if query.ExternalID != "" {
values.Set("external_id", query.ExternalID)
}
if query.Status != nil {
values.Set("status", string(*query.Status))
}
if len(query.Tags) > 0 {
values.Set("tags", strings.Join(query.Tags, ","))
}
if query.MessageSource != nil {
values.Set("message_source", *query.MessageSource)
}
if query.Priority != nil {
values.Set("priority", strconv.Itoa(*query.Priority))
}
if query.Channel != "" {
values.Set("channel", string(query.Channel))
}
if query.Limit != nil {
values.Set("limit", strconv.Itoa(*query.Limit))
}
if query.Offset != nil {
values.Set("offset", strconv.Itoa(*query.Offset))
}
return values
}
81 changes: 81 additions & 0 deletions users.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package lunogram
import (
"context"
"net/http"
"net/url"
"strconv"
"strings"
)

// UpsertUser creates or updates a user profile. The user is identified by
Expand All @@ -28,3 +31,81 @@ func (c *Client) DeleteUser(ctx context.Context, req *DeleteUserRequest) error {
func (c *Client) PostUserEvents(ctx context.Context, events []Event) error {
return c.do(ctx, http.MethodPost, "/api/client/users/events", events, nil)
}

// PostUserInboxMessages creates one or more inbox messages for users.
func (c *Client) PostUserInboxMessages(ctx context.Context, req *PostUserInboxMessagesRequest) error {
return c.do(ctx, http.MethodPost, "/api/client/users/inbox", req, nil)
}

// GetUserInbox retrieves visible, non-expired inbox messages for a user.
func (c *Client) GetUserInbox(ctx context.Context, query *UserInboxQuery) (*InboxMessageList, error) {
path := "/api/client/users/inbox"
if values := userInboxQueryValues(query); len(values) > 0 {
path += "?" + values.Encode()
}

var list InboxMessageList
if err := c.do(ctx, http.MethodGet, path, nil, &list); err != nil {
return nil, err
}
return &list, nil
}

// GetUserInboxCount retrieves unread and total inbox message counts for a user.
func (c *Client) GetUserInboxCount(ctx context.Context, query *UserInboxQuery) (*InboxCount, error) {
path := "/api/client/users/inbox/count"
if values := userInboxQueryValues(query); len(values) > 0 {
path += "?" + values.Encode()
}

var count InboxCount
if err := c.do(ctx, http.MethodGet, path, nil, &count); err != nil {
return nil, err
}
return &count, nil
}

// PostUserInboxOpened marks one or more inbox messages as opened.
func (c *Client) PostUserInboxOpened(ctx context.Context, events *UserInboxMessageEvents) error {
return c.do(ctx, http.MethodPost, "/api/client/users/inbox/opened", events, nil)
}

// PostUserInboxArchived marks one or more inbox messages as archived.
func (c *Client) PostUserInboxArchived(ctx context.Context, events *UserInboxMessageEvents) error {
return c.do(ctx, http.MethodPost, "/api/client/users/inbox/archived", events, nil)
}

func userInboxQueryValues(query *UserInboxQuery) url.Values {
values := url.Values{}
if query == nil {
return values
}
if query.Source != "" {
values.Set("source", query.Source)
}
if query.ExternalID != "" {
values.Set("external_id", query.ExternalID)
}
if query.Status != nil {
values.Set("status", string(*query.Status))
}
if len(query.Tags) > 0 {
values.Set("tags", strings.Join(query.Tags, ","))
}
if query.MessageSource != nil {
values.Set("message_source", *query.MessageSource)
}
if query.Priority != nil {
values.Set("priority", strconv.Itoa(*query.Priority))
}
if query.Channel != "" {
values.Set("channel", string(query.Channel))
}
if query.Limit != nil {
values.Set("limit", strconv.Itoa(*query.Limit))
}
if query.Offset != nil {
values.Set("offset", strconv.Itoa(*query.Offset))
}
return values
}