1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
package ibd
import (
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
)
const (
userInfoUrl = "https://myibd.investors.com/services/userprofile.aspx?format=json"
)
func (c *Client) UserInfo(ctx context.Context, cookie *http.Cookie) (*UserProfile, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, userInfoUrl, nil)
if err != nil {
return nil, err
}
req.AddCookie(cookie)
resp, err := c.Do(req)
if err != nil {
return nil, err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
content, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf(
"unexpected status code %d: %s",
resp.StatusCode,
string(content),
)
}
up := new(UserProfile)
if err = up.UnmarshalJSON(content); err != nil {
return nil, err
}
return up, nil
}
type UserStatus string
const (
UserStatusUnknown UserStatus = ""
UserStatusVisitor UserStatus = "Visitor"
UserStatusSubscriber UserStatus = "Subscriber"
)
type UserProfile struct {
DisplayName string
Email string
FirstName string
LastName string
Status UserStatus
}
func (u *UserProfile) UnmarshalJSON(bytes []byte) error {
var resp userProfileResponse
if err := json.Unmarshal(bytes, &resp); err != nil {
return err
}
u.DisplayName = resp.UserProfile.UserDisplayName
u.Email = resp.UserProfile.UserEmailAddress
u.FirstName = resp.UserProfile.UserFirstName
u.LastName = resp.UserProfile.UserLastName
switch resp.UserProfile.UserTrialStatus {
case "Visitor":
u.Status = UserStatusVisitor
case "Subscriber":
u.Status = UserStatusSubscriber
default:
slog.Warn("Unknown user status", "status", resp.UserProfile.UserTrialStatus)
u.Status = UserStatusUnknown
}
return nil
}
type userProfileResponse struct {
UserProfile userProfile `json:"userProfile"`
}
type userProfile struct {
UserSubType string `json:"userSubType"`
UserId string `json:"userId"`
UserDisplayName string `json:"userDisplayName"`
Countrycode string `json:"countrycode"`
IsEUCountry string `json:"isEUCountry"`
Log string `json:"log"`
AgeGroup string `json:"ageGroup"`
Gender string `json:"gender"`
InvestingExperience string `json:"investingExperience"`
NumberOfTrades string `json:"numberOfTrades"`
Occupation string `json:"occupation"`
TypeOfInvestments string `json:"typeOfInvestments"`
UserEmailAddress string `json:"userEmailAddress"`
UserEmailAddressSHA1 string `json:"userEmailAddressSHA1"`
UserEmailAddressSHA256 string `json:"userEmailAddressSHA256"`
UserEmailAddressMD5 string `json:"userEmailAddressMD5"`
UserFirstName string `json:"userFirstName"`
UserLastName string `json:"userLastName"`
UserZip string `json:"userZip"`
UserTrialStatus string `json:"userTrialStatus"`
UserProductsOnTrial string `json:"userProductsOnTrial"`
UserProductsOwned string `json:"userProductsOwned"`
UserAdTrade string `json:"userAdTrade"`
UserAdTime string `json:"userAdTime"`
UserAdHold string `json:"userAdHold"`
UserAdJob string `json:"userAdJob"`
UserAdAge string `json:"userAdAge"`
UserAdOutSell string `json:"userAdOutSell"`
UserVisitCount string `json:"userVisitCount"`
RoleLeaderboard bool `json:"role_leaderboard"`
RoleOws bool `json:"role_ows"`
RoleIbdlive bool `json:"role_ibdlive"`
RoleFounderclub bool `json:"role_founderclub"`
RoleEibd bool `json:"role_eibd"`
RoleIcom bool `json:"role_icom"`
RoleEtables bool `json:"role_etables"`
RoleTru10 bool `json:"role_tru10"`
RoleMarketsurge bool `json:"role_marketsurge"`
RoleSwingtrader bool `json:"role_swingtrader"`
RoleAdfree bool `json:"role_adfree"`
RoleMarketdiem bool `json:"role_marketdiem"`
RoleWsjPlus bool `json:"role_wsj_plus"`
RoleWsj bool `json:"role_wsj"`
RoleBarrons bool `json:"role_barrons"`
RoleMarketwatch bool `json:"role_marketwatch"`
UserAdRoles string `json:"userAdRoles"`
TrialDailyPrintNeg bool `json:"trial_daily_print_neg"`
TrialDailyPrintNon bool `json:"trial_daily_print_non"`
TrialWeeklyPrintNeg bool `json:"trial_weekly_print_neg"`
TrialWeeklyPrintNon bool `json:"trial_weekly_print_non"`
TrialDailyComboNeg bool `json:"trial_daily_combo_neg"`
TrialDailyComboNon bool `json:"trial_daily_combo_non"`
TrialWeeklyComboNeg bool `json:"trial_weekly_combo_neg"`
TrialWeeklyComboNon bool `json:"trial_weekly_combo_non"`
TrialEibdNeg bool `json:"trial_eibd_neg"`
TrialEibdNon bool `json:"trial_eibd_non"`
UserVideoPreference string `json:"userVideoPreference"`
UserProfessionalStatus bool `json:"userProfessionalStatus"`
}
|