cmd/command_list.go   B
last analyzed

Size/Duplication

Total Lines 217
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 44
eloc 164
dl 0
loc 217
rs 8.8798
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A main.*listT.Validate 0 9 3
A main.newListRunner 0 6 1
F main.getValue 0 48 23
B main.*ListRunner.execAPI 0 24 6
C main.*ListRunner.Run 0 51 9
A main.execList 0 5 1
1
package main
2
3
import (
4
	"fmt"
5
	"strconv"
6
	"strings"
7
	"sync"
8
9
	"github.com/mkideal/cli"
10
11
	"github.com/evalphobia/minfraud-api-go/config"
12
	"github.com/evalphobia/minfraud-api-go/minfraud"
13
)
14
15
var outputHeader = []string{
16
	"ip_address",
17
	"email",
18
	"risk_score",
19
	"ip_risk",
20
	"ip_is_anonymous",
21
	"ip_is_anonymous_vpn",
22
	"ip_is_hosting_provider",
23
	"ip_is_public_proxy",
24
	"ip_is_residential_proxy",
25
	"ip_is_tor_exit_node",
26
	"ip_organization",
27
	"ip_user_count",
28
	"ip_user_type",
29
	"ip_country",
30
	"ip_city",
31
	"ip_registered_country",
32
	"ip_represented_country",
33
	"email_domain_first_seen",
34
	"email_first_seen",
35
	"email_is_disposable",
36
	"email_is_free",
37
	"email_is_high_risk",
38
}
39
40
// parameters of 'list' command.
41
type listT struct {
42
	cli.Helper
43
	Command  string `cli:"*c,command" usage:"set type of api [score, insights, factors] --command='score'"`
44
	InputCSV string `cli:"*i,input" usage:"input csv/tsv file path --input='./input.csv'"`
45
	Output   string `cli:"*o,output" usage:"output tsv file path --output='./output.tsv'"`
46
	Debug    bool   `cli:"debug" usage:"set if you use HTTP debug feature --debug"`
47
}
48
49
func (a *listT) Validate(ctx *cli.Context) error {
50
	if _, ok := validCommands[a.Command]; !ok {
51
		keys := make([]string, 0, len(validCommands))
52
		for k := range validCommands {
53
			keys = append(keys, k)
54
		}
55
		return fmt.Errorf("command should be one of the %v", keys)
56
	}
57
	return nil
58
}
59
60
var listC = &cli.Command{
61
	Name: "list",
62
	Desc: "Exec api call for minFraud API from csv list file",
63
	Argv: func() interface{} { return new(listT) },
64
	Fn:   execList,
65
}
66
67
func execList(ctx *cli.Context) error {
68
	argv := ctx.Argv().(*listT)
69
70
	r := newListRunner(*argv)
71
	return r.Run()
72
}
73
74
type ListRunner struct {
75
	// parameters
76
	Command  string
77
	InputCSV string
78
	Output   string
79
	Debug    bool
80
}
81
82
func newListRunner(p listT) ListRunner {
83
	return ListRunner{
84
		Command:  p.Command,
85
		InputCSV: p.InputCSV,
86
		Output:   p.Output,
87
		Debug:    p.Debug,
88
	}
89
}
90
91
func (r *ListRunner) Run() error {
92
	f, err := NewCSVHandler(r.InputCSV)
93
	if err != nil {
94
		return err
95
	}
96
97
	w, err := NewFileHandler(r.Output)
98
	if err != nil {
99
		return err
100
	}
101
102
	lines, err := f.ReadAll()
103
	if err != nil {
104
		return err
105
	}
106
107
	maxReq := make(chan struct{}, 2)
108
109
	conf := config.Config{
110
		Debug: r.Debug,
111
	}
112
113
	svc, err := minfraud.New(conf)
114
	if err != nil {
115
		return err
116
	}
117
118
	result := make([]string, len(lines))
119
	var wg sync.WaitGroup
120
	for i, line := range lines {
121
		wg.Add(1)
122
		go func(i int, line map[string]string) {
123
			maxReq <- struct{}{}
124
			defer func() {
125
				<-maxReq
126
				wg.Done()
127
			}()
128
129
			fmt.Printf("exec #: [%d]\n", i)
130
			row, err := r.execAPI(svc, line)
131
			if err != nil {
132
				fmt.Printf("[ERROR] #: [%d]; err=[%v]\n", i, err)
133
				return
134
			}
135
			result[i] = strings.Join(row, "\t")
136
		}(i, line)
137
	}
138
	wg.Wait()
139
140
	result = append([]string{strings.Join(outputHeader, "\t")}, result...)
141
	return w.WriteAll(result)
142
}
143
144
func (r *ListRunner) execAPI(svc *minfraud.MinFraud, param map[string]string) ([]string, error) {
145
	params := minfraud.BaseRequest{
146
		Device: &minfraud.DeviceData{},
147
		Email:  &minfraud.EmailData{},
148
	}
149
	if v, ok := param["ip_address"]; ok {
150
		params.Device.IPAddress = v
151
	}
152
	if v, ok := param["email"]; ok {
153
		params.Email.Address = v
154
	}
155
	resp, err := execAPI(svc, params, r.Command)
156
	if err != nil {
157
		return nil, err
158
	}
159
	if resp.HasError() {
160
		return nil, fmt.Errorf("API Error: [%s] [%s]", resp.ErrData.Code, resp.ErrData.Error)
161
	}
162
163
	row := make([]string, 0, len(outputHeader))
164
	for _, v := range outputHeader {
165
		row = append(row, getValue(param, resp, v))
166
	}
167
	return row, nil
168
}
169
170
func getValue(param map[string]string, resp minfraud.APIResponse, name string) string {
171
	switch name {
172
	case "ip_address":
173
		return param["ip_address"]
174
	case "email":
175
		return param["email"]
176
	case "risk_score":
177
		return strconv.FormatFloat(resp.RiskScore, 'f', 5, 64)
178
	case "ip_risk":
179
		return strconv.FormatFloat(resp.IPAddress.Risk, 'f', 5, 64)
180
	case "ip_is_anonymous":
181
		return strconv.FormatBool(resp.IPAddress.Traits.IsAnonymous)
182
	case "ip_is_anonymous_vpn":
183
		return strconv.FormatBool(resp.IPAddress.Traits.IsAnonymousVPN)
184
	case "ip_is_hosting_provider":
185
		return strconv.FormatBool(resp.IPAddress.Traits.IsHostingProvider)
186
	case "ip_is_public_proxy":
187
		return strconv.FormatBool(resp.IPAddress.Traits.IsPublicProxy)
188
	case "ip_is_residential_proxy":
189
		return strconv.FormatBool(resp.IPAddress.Traits.IsResidentialProxy)
190
	case "ip_is_tor_exit_node":
191
		return strconv.FormatBool(resp.IPAddress.Traits.IsTorExitNode)
192
	case "ip_organization":
193
		return resp.IPAddress.Traits.Organization
194
	case "ip_user_count":
195
		return strconv.FormatInt(resp.IPAddress.Traits.UserCount, 10)
196
	case "ip_user_type":
197
		return resp.IPAddress.Traits.UserType
198
	case "ip_country":
199
		return resp.IPAddress.Country.ISOCode
200
	case "ip_city":
201
		return resp.IPAddress.City.Names.EN
202
	case "ip_registered_country":
203
		return resp.IPAddress.RegisteredCountry.ISOCode
204
	case "ip_represented_country":
205
		return resp.IPAddress.RepresentedCountry.ISOCode
206
	case "email_domain_first_seen":
207
		return resp.Email.Domain.FirstSeen
208
	case "email_first_seen":
209
		return resp.Email.FirstSeen
210
	case "email_is_disposable":
211
		return strconv.FormatBool(resp.Email.IsDisposable)
212
	case "email_is_free":
213
		return strconv.FormatBool(resp.Email.IsFree)
214
	case "email_is_high_risk":
215
		return strconv.FormatBool(resp.Email.IsHighRisk)
216
	}
217
	return ""
218
}
219