B: Move to webhook_subscription

This commit is contained in:
Preston Baxter 2023-11-23 09:25:31 -06:00
parent b77f45ccf6
commit a33c58d0d8
6 changed files with 176 additions and 11 deletions

View File

@ -75,7 +75,7 @@ func getAuthSecret(c *gin.Context, body []byte) (string, error) {
return "", fmt.Errorf("There are no events in the delivery. Something is wrong")
}
webhook, err := mongo.FindPcoSubscriptionForUser(*userObjectId, event[0].Name)
webhook, err := mongo.FindPcoWebhookSubscriptionForUser(*userObjectId, event[0].Name)
if err != nil {
return "", errors.Join(fmt.Errorf("Failed to find pco subscription for user: %s and event: %s", userObjectId.Hex(), event[0].Name), err)
}

View File

@ -41,6 +41,36 @@ func (api *PcoApiClient) GetSubscriptions() ([]webhooks.Subscription, error) {
return subscriptions, nil
}
func (api *PcoApiClient) GetWebhookSubscriptions() ([]webhooks.WebhookSubscription, error) {
api.Url().Path = "/webhooks/v2/webhook_subscriptions"
req, err := http.NewRequest(http.MethodGet, api.Url().String(), nil)
if err != nil {
return nil, err
}
resp, err := api.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode > 299 || resp.StatusCode < 200 {
if raw, err := io.ReadAll(resp.Body); err == nil {
return nil, fmt.Errorf("Failed to retrieve subscriptions with status code: %d. Error %s", resp.StatusCode, string(raw))
} else {
return nil, fmt.Errorf("Failed to retrieve subscriptions with status code: %d", resp.StatusCode)
}
}
subscriptions, err := jsonapi.UnmarshalManyPayload[webhooks.WebhookSubscription](resp.Body)
if err != nil {
return nil, err
}
return subscriptions, nil
}
// Posts subscriptions to PCO api and returns a new list of subscriptions
func (api *PcoApiClient) CreateSubscriptions(subscriptions []webhooks.Subscription) ([]webhooks.Subscription, error) {
api.Url().Path = "/webhooks/v2/subscriptions"
@ -114,3 +144,77 @@ func (api *PcoApiClient) CreateSubscription(subscription *webhooks.Subscription)
return nil
}
// Posts subscriptions to PCO api and returns a new list of subscriptions
func (api *PcoApiClient) CreateWebhookSubscriptions(subscriptions []webhooks.WebhookSubscription) ([]webhooks.WebhookSubscription, error) {
api.Url().Path = "/webhooks/v2/webhook_subscriptions"
body := bytes.NewBuffer([]byte{})
err := jsonapi.MarshalPayload(body, subscriptions)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, api.Url().String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/json")
resp, err := api.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode > 299 || resp.StatusCode < 200 {
if raw, err := io.ReadAll(resp.Body); err == nil {
return nil, fmt.Errorf("Failed to create subscriptions with status code: %d. Error %s", resp.StatusCode, string(raw))
} else {
return nil, fmt.Errorf("Failed to create subscriptions with status code: %d", resp.StatusCode)
}
}
new_subscriptions, err := jsonapi.UnmarshalManyPayload[webhooks.WebhookSubscription](resp.Body)
if err != nil {
return nil, err
}
return new_subscriptions, nil
}
// Posts subcription to PCO api and updates the subscription at the pointer that was passed to the fuinction with the server response
func (api *PcoApiClient) CreateWebhookSubscription(subscription *webhooks.WebhookSubscription) error {
api.Url().Path = "/webhooks/v2/webhook_subscriptions"
body := bytes.NewBuffer([]byte{})
err := jsonapi.MarshalPayload(body, subscription)
if err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, api.Url().String(), body)
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json")
resp, err := api.Do(req)
if err != nil {
return err
}
if resp.StatusCode > 299 || resp.StatusCode < 200 {
if raw, err := io.ReadAll(resp.Body); err == nil {
return fmt.Errorf("Failed to create subscriptions with status code: %d. Error %s", resp.StatusCode, string(raw))
} else {
return fmt.Errorf("Failed to create subscription with status code: %d", resp.StatusCode)
}
}
err = jsonapi.UnmarshalPayload(resp.Body, subscription)
if err != nil {
return err
}
return nil
}

View File

@ -16,8 +16,8 @@ import (
type actionFunc func(user *models.User) error
var (
actionFuncs map[string]actionFunc = map[string]actionFunc{"pco.plan": setupPcoSubscriptions}
webhooksTemplate map[string]webhooks.Subscription = map[string]webhooks.Subscription{
actionFuncs map[string]actionFunc = map[string]actionFunc{"pco.plan": setupPcoSubscriptions}
webhooksTemplate map[string]webhooks.WebhookSubscription = map[string]webhooks.WebhookSubscription{
"services.v2.events.plan.created": {
Active: true,
Name: "services.v2.events.plan.created",
@ -114,8 +114,8 @@ func setupPcoSubscriptions(user *models.User) error {
pcoApi := pco.NewClientWithOauthConfig(conf.Vendors[models.PCO_VENDOR_NAME].OauthConfig(), tokenSource)
//Check if subscriptions already exist
webhookMap := make(map[string]webhooks.Subscription)
subscriptions, err := pcoApi.GetSubscriptions()
webhookMap := make(map[string]webhooks.WebhookSubscription)
subscriptions, err := pcoApi.GetWebhookSubscriptions()
if err != nil {
return errors.Join(fmt.Errorf("Failed to find subscriptions for user: %s", user.Id), err)
}
@ -131,11 +131,11 @@ func setupPcoSubscriptions(user *models.User) error {
}
}
builtHooks := make([]webhooks.Subscription, 0, len(webhooksTemplate))
builtHooks := make([]webhooks.WebhookSubscription, 0, len(webhooksTemplate))
//Build subscriptions
for _, templ := range webhooksTemplate {
if _, ok := webhookMap[templ.Name]; !ok {
builtHooks = append(builtHooks, webhooks.Subscription{
builtHooks = append(builtHooks, webhooks.WebhookSubscription{
Active: true,
Name: templ.Name,
Url: fmt.Sprintf(templ.Url, conf.AppSettings.WebhookServiceUrl, user.Id.Hex()),
@ -145,14 +145,14 @@ func setupPcoSubscriptions(user *models.User) error {
//Todo: save subscriptions for succesfull hooksetups
for index := range builtHooks {
err = pcoApi.CreateSubscription(&builtHooks[index])
err = pcoApi.CreateWebhookSubscription(&builtHooks[index])
if err != nil {
return errors.Join(fmt.Errorf("Failed to create subscription: %s for user: %s", builtHooks[index].Name ,user.Id), err)
return errors.Join(fmt.Errorf("Failed to create subscription: %s for user: %s", builtHooks[index].Name, user.Id), err)
}
}
//Save Subscriptions
err = mongo.SaveSubscriptionsForUser(user.Id, builtHooks...)
err = mongo.SaveWebhookSubscriptionsForUser(user.Id, builtHooks...)
if err != nil {
return errors.Join(fmt.Errorf("Failed to save subscriptions for user: %s", user.Id), err)
}

View File

@ -34,3 +34,29 @@ func (obj *PcoSubscription) UpdateObjectInfo() {
}
obj.UpdatedAt = now
}
type PcoWebhookSubscription struct {
*CommonFields `bson:"obj_info"`
Id primitive.ObjectID `bson:"_id,omitempty"`
UserId primitive.ObjectID `bson:"user_id,omitempty"`
Details *webhooks.WebhookSubscription `bson:"details,omitempty"`
}
func (obj *PcoWebhookSubscription) MongoId() primitive.ObjectID {
if obj.Id.IsZero() {
now := time.Now()
obj.Id = primitive.NewObjectIDFromTimestamp(now)
}
return obj.Id
}
func (obj *PcoWebhookSubscription) UpdateObjectInfo() {
now := time.Now()
if obj.CommonFields == nil {
obj.CommonFields = new(CommonFields)
obj.EntityType = PCO_SUBSCRIPTION_TYPE
obj.CreatedAt = now
}
obj.UpdatedAt = now
}

View File

@ -35,6 +35,29 @@ func (db *DB) FindPcoSubscriptionForUser(userId primitive.ObjectID, eventName st
return subscription, nil
}
// using userId and event string return PCO Subscriptions saved to the DB
func (db *DB) FindPcoWebhookSubscriptionForUser(userId primitive.ObjectID, eventName string) (*models.PcoWebhookSubscription, error) {
conf := config.Config()
opts := options.FindOne()
res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"user_id": userId, "obj_info.ent": models.PCO_SUBSCRIPTION_TYPE, "details.name": eventName}, opts)
if res.Err() != nil {
if res.Err() == mongo.ErrNoDocuments {
return nil, nil
}
return nil, res.Err()
}
subscription := &models.PcoWebhookSubscription{}
err := res.Decode(subscription)
if err != nil {
return nil, err
}
return subscription, nil
}
// Okay so learned something here. Interfaces are determined implemented for the type a method is related to.
// This function is not implemented for DB it is implemented for *DB and that is important
func (db *DB) SaveSubscriptionsForUser(userId primitive.ObjectID, subscriptions ...webhooks.Subscription) error {
@ -48,3 +71,15 @@ func (db *DB) SaveSubscriptionsForUser(userId primitive.ObjectID, subscriptions
return saveModels(db, mods...)
}
func (db *DB) SaveWebhookSubscriptionsForUser(userId primitive.ObjectID, subscriptions ...webhooks.WebhookSubscription) error {
mods := make([]*models.PcoWebhookSubscription, 0, len(subscriptions))
for _, sub := range subscriptions {
mods = append(mods, &models.PcoWebhookSubscription{
UserId: userId,
Details: &sub,
})
}
return saveModels(db, mods...)
}

View File

@ -1,4 +1,4 @@
{
"webhook_version": "0.0.48",
"webhook_version": "0.0.49",
"frontend_version": "0.0.35"
}