Skip to content

Commit

Permalink
Feat/fs3 1550 (#5)
Browse files Browse the repository at this point in the history
* fix: Add new aliases for WE & FE

* fix: Read output-format var in request file

* chore: Set working dir, identifier and email when switching account and login

* feat: Add sendHitAnalytics when requesting

* fix: Add responser for /users/me and fix test
  • Loading branch information
Chadiii authored Nov 4, 2024
1 parent 6752203 commit cd936fc
Show file tree
Hide file tree
Showing 13 changed files with 263 additions and 8 deletions.
2 changes: 1 addition & 1 deletion cmd/feature-experimentation/feature_experimentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
// FeatureExperimentationCmd represents the feature experimentation command
var FeatureExperimentationCmd = &cobra.Command{
Use: "feature-experimentation [auth|account|account-environment|project|campaign|flag|goal|targeting-key|variation-group|variation]",
Aliases: []string{"feature-experimentation", "feature-exp", "fe", "feat-exp"},
Aliases: []string{"feature-experimentation", "feature-exp", "fe", "feat-exp", "feature"},
Short: "Manage resources related to the feature experimentation product",
Long: `Manage resources related to the feature experimentation product`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
Expand Down
4 changes: 1 addition & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import (
"github.com/spf13/viper"
)

var outputFormat string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "abtasty-cli",
Expand Down Expand Up @@ -55,7 +53,7 @@ func addSubCommandPalettes() {
func init() {
cobra.OnInitialize(initConfig)

RootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "", config.OutputFormat, "output format for the get and list subcommands for AB Tasty resources. Only 3 format are possible: table, json, json-pretty")
RootCmd.PersistentFlags().StringVarP(&common.OutputFormat, "output-format", "", config.OutputFormat, "output format for the get and list subcommands for AB Tasty resources. Only 3 format are possible: table, json, json-pretty")
RootCmd.PersistentFlags().StringVarP(&common.UserAgent, "user-agent", "", config.DefaultUserAgent, "custom user agent")

viper.BindPFlag("output_format", RootCmd.PersistentFlags().Lookup("output-format"))
Expand Down
24 changes: 24 additions & 0 deletions cmd/web-experimentation/account/use.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"fmt"
"log"

"github.com/flagship-io/abtasty-cli/models/web_experimentation"
"github.com/flagship-io/abtasty-cli/utils"
"github.com/flagship-io/abtasty-cli/utils/config"
"github.com/flagship-io/abtasty-cli/utils/http_request/common"
"github.com/spf13/cobra"
)

Expand All @@ -28,6 +30,28 @@ var useCmd = &cobra.Command{
log.Fatalf("error occurred: %s", err)
}

err = config.SetWorkingDir(utils.WEB_EXPERIMENTATION, utils.DefaultGlobalCodeWorkingDir())
if err != nil {
log.Fatalf("error occurred: %s", err)
}

currentUser, err := common.HTTPGetIdentifierWE()
if err != nil {
log.Fatalf("error occurred: %v", err)
}

if currentUser.LastAccount != (web_experimentation.AccountWE{}) {
err := config.SetIdentifier(utils.WEB_EXPERIMENTATION, currentUser.LastAccount.Identifier)
if err != nil {
log.Fatalf("error occurred: %s", err)
}

err = config.SetEmail(utils.WEB_EXPERIMENTATION, currentUser.Email)
if err != nil {
log.Fatalf("error occurred: %s", err)
}
}

fmt.Fprintln(cmd.OutOrStdout(), "Account ID set to : "+AccountID)

},
Expand Down
35 changes: 35 additions & 0 deletions cmd/web-experimentation/auth/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"slices"

"github.com/flagship-io/abtasty-cli/models/web_experimentation"
"github.com/flagship-io/abtasty-cli/utils"
"github.com/flagship-io/abtasty-cli/utils/config"
"github.com/flagship-io/abtasty-cli/utils/http_request/common"
Expand Down Expand Up @@ -80,6 +81,23 @@ var loginCmd = &cobra.Command{
log.Fatalf("error occurred: %v", err)
}

currentUser, err := common.HTTPGetIdentifierWE()
if err != nil {
log.Fatalf("error occurred: %v", err)
}

if currentUser.LastAccount != (web_experimentation.AccountWE{}) {
err := config.SetIdentifier(utils.WEB_EXPERIMENTATION, currentUser.LastAccount.Identifier)
if err != nil {
log.Fatalf("error occurred: %s", err)
}

err = config.SetEmail(utils.WEB_EXPERIMENTATION, currentUser.Email)
if err != nil {
log.Fatalf("error occurred: %s", err)
}
}

if AccountID != "" {
err = config.SetAccountID(utils.WEB_EXPERIMENTATION, AccountID)
if err != nil {
Expand Down Expand Up @@ -111,6 +129,23 @@ var loginCmd = &cobra.Command{
log.Fatalf("error occurred: %v", err)
}

currentUser, err := common.HTTPGetIdentifierWE()
if err != nil {
log.Fatalf("error occurred: %v", err)
}

if currentUser.LastAccount != (web_experimentation.AccountWE{}) {
err := config.SetIdentifier(utils.WEB_EXPERIMENTATION, currentUser.LastAccount.Identifier)
if err != nil {
log.Fatalf("error occurred: %s", err)
}

err = config.SetEmail(utils.WEB_EXPERIMENTATION, currentUser.Email)
if err != nil {
log.Fatalf("error occurred: %s", err)
}
}

if AccountID != "" {
err = config.SetAccountID(utils.WEB_EXPERIMENTATION, AccountID)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/web-experimentation/web_experimentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
// WebExperimentationCmd represents the web experimentation command
var WebExperimentationCmd = &cobra.Command{
Use: "web-experimentation [auth|account|campaign|global-code|variation]",
Aliases: []string{"web-experimentation", "web-exp", "we"},
Aliases: []string{"web-experimentation", "web-exp", "we", "web"},
Short: "Manage resources related to the web experimentation product",
Long: `Manage resources related to the web experimentation product`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
Expand Down
12 changes: 12 additions & 0 deletions models/token.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package models

import models "github.com/flagship-io/abtasty-cli/models/web_experimentation"

type MfaRequestWE struct {
MfaToken string `json:"mfa_token"`
MfaMethods []string `json:"mfa_methods"`
Expand Down Expand Up @@ -37,6 +39,16 @@ type TokenResponse struct {
Scope string `json:"scope"`
}

type UserMe struct {
Id int `json:"id,omitempty"`
Email string `json:"email"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Societe string `json:"societe"`
IsABTasty bool `json:"is_abtasty"`
LastAccount models.AccountWE `json:"last_account"`
}

type ClientCredentialsRequest struct {
GrantType string `json:"grant_type"`
Scope string `json:"scope,omitempty"`
Expand Down
40 changes: 40 additions & 0 deletions utils/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,46 @@ func SetAccountID(product, accountID string) error {
return nil
}

func SetIdentifier(product, identifier string) error {
var v = viper.New()
configFilepath, err := CredentialPath(product, utils.HOME_CLI)
if err != nil {
return err
}

v.SetConfigFile(configFilepath)
v.MergeInConfig()

v.Set("identifier", identifier)

err = v.WriteConfigAs(configFilepath)
if err != nil {
return err
}

return nil
}

func SetEmail(product string, email string) error {
var v = viper.New()
configFilepath, err := CredentialPath(product, utils.HOME_CLI)
if err != nil {
return err
}

v.SetConfigFile(configFilepath)
v.MergeInConfig()

v.Set("email", email)

err = v.WriteConfigAs(configFilepath)
if err != nil {
return err
}

return nil
}

func SetWorkingDir(product, path string) error {
var v = viper.New()
configFilepath, err := CredentialPath(product, utils.HOME_CLI)
Expand Down
1 change: 1 addition & 0 deletions utils/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ func DefaultGlobalCodeWorkingDir() string {
const FEATURE_EXPERIMENTATION = "fe"
const WEB_EXPERIMENTATION = "we"
const HOME_CLI = ".cli"
const HIT_ANALYTICS_URL = "https://events.flagship.io/analytics"
92 changes: 92 additions & 0 deletions utils/http_request/common/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
)

var UserAgent string
var OutputFormat string

var c = http.Client{Timeout: time.Duration(10) * time.Second}
var counter = false
Expand All @@ -35,6 +36,8 @@ type ResourceRequest struct {
AccountID string `mapstructure:"account_id"`
AccountEnvironmentID string `mapstructure:"account_environment_id"`
WorkingDir string `mapstructure:"working_dir"`
Identifier string `mapstructure:"identifier"`
Email string `mapstructure:"email"`
}

func (c *ResourceRequest) Init(cL *RequestConfig) {
Expand Down Expand Up @@ -68,6 +71,30 @@ type RequestConfig struct {
CurrentUsedCredential string `mapstructure:"current_used_credential"`
OutputFormat string `mapstructure:"output_format"`
WorkingDirectory string `mapstructure:"working_dir"`
Identifier string `mapstructure:"identifier"`
Email string `mapstructure:"email"`
}

type HitRequest struct {
DS string `json:"ds"`
ClientID string `json:"cid"`
VisitorID string `json:"vid"`
Type string `json:"t"`
CustomVariable CustomVariableRequest `json:"cv"`
}

type CustomVariableRequest struct {
Version string `json:"version"`
Timestamp string `json:"timestamp"`
StackType string `json:"stack.type"`
UserAgent string `json:"user.agent"`
OutputFormat string `json:"output.format"`
EnvironmentId string `json:"envId"`
AccountId string `json:"accountId"`
HttpMethod string `json:"http.method"`
HttpURL string `json:"http.url"`
ABTastyProduct string `json:"abtasty.product"`
Identifier string `json:"identifier"`
}

var cred RequestConfig
Expand Down Expand Up @@ -106,6 +133,10 @@ func regenerateToken(product, configName string) {
}

func HTTPRequest[T any](method string, url string, body []byte) ([]byte, error) {
if !strings.Contains(cred.Email, "@abtasty.com") && (utils.WEB_EXPERIMENTATION == cred.Product || (utils.FEATURE_EXPERIMENTATION == cred.Product && cred.AccountEnvironmentID != "")) {
sendAnalyticHit(method, url)
}

var bodyIO io.Reader = nil
if body != nil {
bodyIO = bytes.NewBuffer(body)
Expand Down Expand Up @@ -261,3 +292,64 @@ func HTTPGetAllPagesWE[T any](resource string) ([]T, error) {
}
return results, nil
}

func sendAnalyticHit(method string, url string) (int, error) {
var bodyIO io.Reader = nil
var clientID = ""

if cred.Product == utils.FEATURE_EXPERIMENTATION {
clientID = cred.AccountEnvironmentID
}

if cred.Product == utils.WEB_EXPERIMENTATION {
clientID = cred.Identifier
}

var customVariable = CustomVariableRequest{
Version: "1",
Timestamp: time.Now().UTC().Format("2006-01-02T15:04:05.000Z"),
StackType: "Tools",
UserAgent: UserAgent,
ABTastyProduct: cred.Product,
EnvironmentId: cred.AccountEnvironmentID,
Identifier: cred.Identifier,
AccountId: cred.AccountID,
HttpMethod: method,
HttpURL: url,
OutputFormat: OutputFormat,
}

var hit = HitRequest{
DS: "APP",
ClientID: clientID,
VisitorID: cred.AccountID,
Type: "USAGE",
CustomVariable: customVariable,
}

body, err := json.Marshal(hit)
if err != nil {
log.Fatalf("error occurred: %v", err)
}

if body != nil {
bodyIO = bytes.NewBuffer(body)
}

req, err := http.NewRequest(http.MethodPost, utils.HIT_ANALYTICS_URL, bodyIO)
if err != nil {
log.Panicf("error occurred on request creation: %v", err)
}

req.Header.Add("Accept", `*/*`)
req.Header.Add("Accept-Encoding", `gzip, deflate, br`)
req.Header.Add("Content-Type", "application/json")

resp, err := c.Do(req)
if err != nil {
return 0, err
}
defer resp.Body.Close()

return resp.StatusCode, nil
}
16 changes: 16 additions & 0 deletions utils/http_request/common/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ func HTTPRefreshTokenWE(cred RequestConfig) (models.TokenResponse, error) {
return authenticationResponse, err
}

func HTTPGetIdentifierWE() (models.UserMe, error) {
var currentUser models.UserMe

respBody, err := HTTPRequest[models.Token](http.MethodGet, utils.GetWebExperimentationHost()+"/v1"+"/users"+"/me", nil)
if err != nil {
return models.UserMe{}, err
}

err = json.Unmarshal(respBody, &currentUser)
if err != nil {
return models.UserMe{}, err
}

return currentUser, err
}

func InitiateBrowserAuth(username, clientID, clientSecret string) (models.TokenResponse, error) {
if clientID == "" || clientSecret == "" {
log.Fatal("Error while login, required fields (username, client ID, client secret)")
Expand Down
11 changes: 8 additions & 3 deletions utils/http_request/web_experimentation/account.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package web_experimentation

import (
models "github.com/flagship-io/abtasty-cli/models/web_experimentation"
"github.com/flagship-io/abtasty-cli/models"
models_ "github.com/flagship-io/abtasty-cli/models/web_experimentation"
"github.com/flagship-io/abtasty-cli/utils"
"github.com/flagship-io/abtasty-cli/utils/http_request/common"
)
Expand All @@ -10,6 +11,10 @@ type AccountWERequester struct {
*common.ResourceRequest
}

func (a *AccountWERequester) HTTPListAccount() ([]models.AccountWE, error) {
return common.HTTPGetAllPagesWE[models.AccountWE](utils.GetWebExperimentationHost() + "/v1/accounts?")
func (a *AccountWERequester) HTTPListAccount() ([]models_.AccountWE, error) {
return common.HTTPGetAllPagesWE[models_.AccountWE](utils.GetWebExperimentationHost() + "/v1/accounts?")
}

func HTTPUserMe() (models.UserMe, error) {
return common.HTTPGetItem[models.UserMe](utils.GetWebExperimentationHost() + "/v1/users/me")
}
15 changes: 15 additions & 0 deletions utils/http_request/web_experimentation/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,18 @@ func TestHTTPListAccount(t *testing.T) {
assert.Equal(t, "account_role", respBody[0].Role)

}

func TestHTTPUserMe(t *testing.T) {

respBody, err := HTTPUserMe()

assert.NotNil(t, respBody)
assert.Nil(t, err)

assert.Equal(t, 100000, respBody.Id)
assert.Equal(t, "[email protected]", respBody.Email)
assert.Equal(t, "john", respBody.FirstName)
assert.Equal(t, "doe", respBody.LastName)
assert.Equal(t, "Example", respBody.Societe)
assert.Equal(t, false, respBody.IsABTasty)
}
Loading

0 comments on commit cd936fc

Please sign in to comment.