Our team is developing a software platform for sending notifications via REST API to mobile devices. These are currently push notifications for iOS devices, as well as SMS due to integration with Twilio ). In order to organize the support process, as well as the user community, a number of information systems and services was selected (see list below), which, from our point of view, made it possible to solve the problem in the shortest possible time and with minimal effort.
Automate the following:
All of the following information systems and services have a REST API interface that allows you to solve tasks.
In our case, the following events are exhaustive:
First of all, the source of all the above events of the process is the Paddle platform, namely their Events / Alerts subsystem. When a certain event occurs, Paddle initiates a POST request to a predetermined URL (of our server).
Events that we will handle:
The request from the side of Paddle contains the following information (the content of the request from the side of Paddle may differ depending on the events described above, but the elements of interest remain the same in any case):
{ "method": "POST", "data": { "alert_id": "XXXXXX", "alert_name": "subscription_created", "cancel_url": "https://checkout.paddle.com/subscription/cancel?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "currency": "USD", "email": "name@example.com", "event_time": "2016-08-05 13:26:06", "next_bill_date": "2017-08-05", "passthrough": "", "status": "active", "subscription_id": "XXXXXX", "subscription_plan_id": "XXXXXX", "update_url": "https://checkout.paddle.com/subscription/update?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "p_signature": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } }
and expects HTTP 200 OK in response:
{ "http_code": 200, "redirect_url": "", "content_type": "text/plain; charset=utf-8", "total_time": 1.018837 }
In case the answer differs from HTTP 200 OK , Paddle will send a repeated request towards our server for 72 hours with an interval of once per hour.
In the above request from Paddle, we are interested in the alert_name and email parameters that we will use to register users in our information systems.
type Event struct { AlertName string `form:"alert_name" binding:"required"` Email string `form:"email" binding:"required"` Status string `form:"status"` SubscriptionId int `form:"subscription_id"` OrderId string `form:"order_id"` SubscriptionPlanId int `form:"subscription_plan_id"` Country string `form:"country"` Fee float32 `form:"fee"` Currency string `form:"currency"` Psignature string `form:"p_signature"` Passthrough string `form:"passthrough"` PaymentMethod string `form:"payment_method"` PaymentTax float32 `form:"payment_tax"` SaleGross float32 `form:"sale_gross"` Earnings float32 `form:"earnings"` EventTime string `form:"event_time"` NextBillDate string `form:"next_bill_date"` } func (e *Event) ToFields() (fields log.Fields) { fields = make(log.Fields) fields["alert_name"] = e.AlertName fields["email"] = e.Email fields["status"] = e.Status fields["subscription_id"] = e.SubscriptionId fields["order_id"] = e.OrderId fields["subscription_plan_id"] = e.SubscriptionPlanId fields["country"] = e.Country fields["fee"] = e.Fee fields["currency"] = e.Currency fields["p_signature"] = e.Psignature fields["passthrough"] = e.Passthrough fields["payment_method"] = e.PaymentMethod fields["payment_tax"] = e.PaymentTax fields["sale_gross"] = e.SaleGross fields["earnings"] = e.Earnings fields["event_time"] = e.EventTime fields["next_bill_date"] = e.NextBillDate return }
func eventPOST(c *gin.Context) { status := []bool{} c.Bind(&event) log.WithFields(event.ToFields()).Info("Processing event") switch event.AlertName { case "subscription_created": status = append(status, InviteToJira(event.Email)) status = append(status, AddToJiraGroup(event.Email)) status = append(status, InviteToSlack(event.Email)) case "payment_succeeded": status = append(status, InviteToJira(event.Email)) status = append(status, InviteToSlack(event.Email)) case "subscription_cancelled": status = append(status, RemoveFromJiraGroup(event.Email)) default: status = append(status, false) log.WithFields(log.Fields{ "event": event.AlertName, }).Error("Unknown event") } for _, s := range status { if s == false { c.String(http.StatusInternalServerError, "not Ok\n") return } } c.String(http.StatusOK, "Ok\n") return }
Further, depending on the received event, we will process them accordingly.
func InviteToSlack(username string) bool { api := slack.New(Conf.Slack.Token) err := api.InviteToTeam(Conf.Slack.Team, "", "", username) if err != nil { if strings.Contains(err.Error(), "already_in_team") { log.WithFields(log.Fields{ "user": username, "slack_team": Conf.Slack.Team, }).Warn("User already in Slack team") return true } else if strings.Contains(err.Error(), "already_invited") { log.WithFields(log.Fields{ "user": username, "slack_team": Conf.Slack.Team, }).Warn("User already invited to Slack") return true } log.Error(err) return false } log.WithFields(log.Fields{ "user": username, }).Warn("User successfuly invited to Slack") return true }
func InviteToJira(username string) bool { jira := jira.New(Conf.Jira.Host, Conf.Jira.User, Conf.Jira.Password, false) _, err := jira.GetUser(username) if err != nil { if err.Error() == "Not Found" { ok, err := jira.InviteSdUser(username, Conf.Jira.Invite_uri) if ok { log.WithFields(log.Fields{ "user": username, }).Info("Invited user to JIRA") return true } else { log.WithFields(log.Fields{ "user": username, "error": err, }).Error("Invite to JIRA Failed") return false } } else { log.Error(err) return false } } log.WithFields(log.Fields{ "user": username, }).Warn("User already Invited to JIRA") return true }
func AddToJiraGroup(username string) bool { jira := jira.New(Conf.Jira.Host, Conf.Jira.User, Conf.Jira.Password, false) ok, err := jira.AddToGroup(username, Conf.Jira.Invite_group) if ok { log.WithFields(log.Fields{ "user": username, "group": Conf.Jira.Invite_group, }).Info("Added user to Jira Group") return true } else { log.WithFields(log.Fields{ "user": username, "group": Conf.Jira.Invite_group, "error": err, }).Error("Failed to add user to Jira Group") return false } }
func RemoveFromJiraGroup(username string) bool { jira := jira.New(Conf.Jira.Host, Conf.Jira.User, Conf.Jira.Password, false) ok, err := jira.RemoveFromGroup(username, Conf.Jira.Invite_group) if ok { log.WithFields(log.Fields{ "user": username, "group": Conf.Jira.Invite_group, }).Info("Removed user from Jira Group") return true } else { log.WithFields(log.Fields{ "user": username, "group": Conf.Jira.Invite_group, "error": err, }).Error("Failed to remove User from Jira Group") return false } }
The source code for the solution described above is available on GitHub: paddle-endpoint .
Thank you for attention!
Source: https://habr.com/ru/post/307344/
All Articles