diff --git a/service/vendors/pco/pco.go b/service/vendors/pco/pco.go index 080cedf..acbf929 100644 --- a/service/vendors/pco/pco.go +++ b/service/vendors/pco/pco.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" + "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models" "golang.org/x/oauth2" ) diff --git a/ui/config/config.go b/ui/config/config.go index 65ebc58..be3d9e3 100644 --- a/ui/config/config.go +++ b/ui/config/config.go @@ -8,10 +8,16 @@ import ( ) type config struct { - Mongo *MongoConfig `mapstructure:"mongo"` - Vendors map[string]*VendorConfig `mapstructure:"vendors"` - JwtSecret string `mapstructure:"jwt_secret"` - Env string `mapstructure:"env"` + Mongo *MongoConfig `mapstructure:"mongo"` + Vendors map[string]*VendorConfig `mapstructure:"vendors"` + JwtSecret string `mapstructure:"jwt_secret"` + Env string `mapstructure:"env"` + AppSettings *AppSettings `mapstructure:"app_settings"` +} + +type AppSettings struct { + WebhookServiceUrl string `mapstructure:"webhook_service_url"` + FrontendServiceUrl string `mapstructure:"frontend_service_url"` } type MongoConfig struct { diff --git a/ui/controllers/actions.go b/ui/controllers/actions.go index 4d591eb..a94e4aa 100644 --- a/ui/controllers/actions.go +++ b/ui/controllers/actions.go @@ -1,10 +1,38 @@ package controllers import ( + "fmt" "strings" + "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config" "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models" + "git.preston-baxter.com/Preston_PLB/capstone/webhook-service/vendors/pco" + "git.preston-baxter.com/Preston_PLB/capstone/webhook-service/vendors/pco/webhooks" "github.com/gin-gonic/gin" + "golang.org/x/oauth2" +) + +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{ + "services.v2.events.plan.created": { + Active: true, + Name: "services.v2.events.plan.created", + Url: "https://%s/pco/%s", + }, + "services.v2.events.plan.updated": { + Active: true, + Name: "services.v2.events.plan.updated", + Url: "https://%s/pco/%s", + }, + "services.v2.events.plan.deleted": { + Active: true, + Name: "services.v2.events.plan.deleted", + Url: "https://%s/pco/%s", + }, + } ) func AddActionFromForm(c *gin.Context) { @@ -37,10 +65,17 @@ func AddActionFromForm(c *gin.Context) { return } - //setup action - - // + //setup action listener + if afunc, ok := actionFuncs[strings.Join(source, ".")]; ok { + err := afunc(user) + if err != nil { + log.WithError(err).Error("Failed to setup actions") + serverError(c, "Failed to setup actions") + return + } + } + //Build mappings am := &models.ActionMapping{ UserId: user.Id, SourceEvent: &models.Event{ @@ -59,3 +94,57 @@ func AddActionFromForm(c *gin.Context) { c.Redirect(302, "/dashboard") } + +func setupPcoSubscriptions(user *models.User) error { + // Get PCO vendor account + conf := config.Config() + pcoAccount, err := mongo.FindVendorAccountByUser(user.Id, models.PCO_VENDOR_NAME) + if err != nil { + return err + } + + //build pco api + tokenSource := oauth2.ReuseTokenSource(pcoAccount.Token(), mongo.NewVendorTokenSource(pcoAccount)) + 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() + //Loop through found subscriptions + for _, sub := range subscriptions{ + //if subsciption is in the templates look to add it to our map + if templ, ok := webhooksTemplate[sub.Name]; ok { + //if the subscription is for our url add it to our map + url := fmt.Sprintf(templ.Url, conf.AppSettings.WebhookServiceUrl, user.Id.Hex()) + if url == sub.Url { + webhookMap[sub.Name] = sub + } + } + } + + builtHooks := make([]webhooks.Subscription, 0, len(webhooksTemplate)) + //Build subscriptions + for _, templ := range webhooksTemplate { + if _, ok := webhookMap[templ.Name]; !ok { + builtHooks = append(builtHooks, webhooks.Subscription{ + Active: false, + Name: templ.Name, + Url: fmt.Sprintf(templ.Url, conf.AppSettings.WebhookServiceUrl, user.Id.Hex()), + }) + } + } + + //Post Subscriptions + subscriptions, err = pcoApi.CreateSubscriptions(builtHooks) + if err != nil { + return err + } + + //Save Subscriptions + err = mongo.SaveSubscriptionsForUser(user.Id, subscriptions...) + if err != nil { + return err + } + + return nil +} diff --git a/ui/db/db.go b/ui/db/db.go index c9d54c6..dcd1087 100644 --- a/ui/db/db.go +++ b/ui/db/db.go @@ -81,6 +81,35 @@ func (db *DB) SaveModels(m ...Model) error { return nil } +//For allowing more varidaic like things +func saveModels[T Model](db *DB, m ...T) error { + conf := config.Config() + + writeEntry := make([]mongo.WriteModel, len(m)) + + for index, model := range m { + entry := mongo.NewUpdateOneModel() + entry.SetFilter(bson.M{"_id": model.MongoId}) + entry.SetUpsert(true) + entry.SetUpdate(bson.M{"$set": model}) + model.UpdateObjectInfo() + + writeEntry[index] = entry + } + + opts := options.BulkWrite() + res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).BulkWrite(context.Background(), writeEntry, opts) + if err != nil { + return err + } + + if res.MatchedCount == 0 && res.ModifiedCount == 0 && res.UpsertedCount == 0 { + return errors.New("Failed to save models properly") + } + + return nil +} + // Doesn't upsert func (db *DB) InsertModel(m Model) error { conf := config.Config() diff --git a/ui/db/pco.go b/ui/db/pco.go index 73bfd56..008ada4 100644 --- a/ui/db/pco.go +++ b/ui/db/pco.go @@ -5,6 +5,7 @@ import ( "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config" "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models" + "git.preston-baxter.com/Preston_PLB/capstone/webhook-service/vendors/pco/webhooks" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -33,3 +34,17 @@ func (db *DB) FindPcoSubscriptionForUser(userId primitive.ObjectID, eventName st 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) { + mods := make([]*models.PcoSubscription, 0, len(subscriptions)) + for _, sub := range subscriptions { + mods = append(mods, &models.PcoSubscription{ + UserId: userId, + Details: &sub, + }) + } + + return saveModels(db, mods...) +}