-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinbox.go
More file actions
312 lines (287 loc) · 11.4 KB
/
inbox.go
File metadata and controls
312 lines (287 loc) · 11.4 KB
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
package casparser
import (
"context"
"fmt"
"net/http"
"slices"
"time"
"github.com/CASParser/cas-parser-go/internal/apijson"
"github.com/CASParser/cas-parser-go/internal/requestconfig"
"github.com/CASParser/cas-parser-go/option"
"github.com/CASParser/cas-parser-go/packages/param"
"github.com/CASParser/cas-parser-go/packages/respjson"
)
// Endpoints for importing CAS files directly from user email inboxes.
//
// **Supported Providers:** Gmail (more coming soon)
//
// **How it works:**
//
// 1. Call `POST /v4/inbox/connect` to get an OAuth URL
// 2. Redirect user to the OAuth URL for consent
// 3. User is redirected back to your `redirect_uri` with an encrypted
// `inbox_token`
// 4. Use the token to list/fetch CAS files from their inbox (`/v4/inbox/cas`)
// 5. Files are uploaded to temporary cloud storage (URLs expire in 24 hours)
//
// **Security:**
//
// - Read-only access (we cannot send emails)
// - Tokens are encrypted with server-side secret
// - User can revoke access anytime via `/v4/inbox/disconnect`
//
// InboxService contains methods and other services that help with interacting with
// the cas-parser API.
//
// Note, unlike clients, this service does not read variables from the environment
// automatically. You should not instantiate this service directly, and instead use
// the [NewInboxService] method instead.
type InboxService struct {
Options []option.RequestOption
}
// NewInboxService generates a new service that applies the given options to each
// request. These options are applied after the parent client's options (if there
// is one), and before any request-specific options.
func NewInboxService(opts ...option.RequestOption) (r InboxService) {
r = InboxService{}
r.Options = opts
return
}
// Verify if an `inbox_token` is still valid and check connection status.
//
// Use this to check if the user needs to re-authenticate (e.g., if they revoked
// access in their email provider settings).
func (r *InboxService) CheckConnectionStatus(ctx context.Context, body InboxCheckConnectionStatusParams, opts ...option.RequestOption) (res *InboxCheckConnectionStatusResponse, err error) {
if !param.IsOmitted(body.XInboxToken) {
opts = append(opts, option.WithHeader("x-inbox-token", fmt.Sprintf("%v", body.XInboxToken)))
}
opts = slices.Concat(r.Options, opts)
path := "v4/inbox/status"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
return res, err
}
// Initiate OAuth flow to connect user's email inbox.
//
// Returns an `oauth_url` that you should redirect the user to. After
// authorization, they are redirected back to your `redirect_uri` with the
// following query parameters:
//
// **On success:**
//
// - `inbox_token` - Encrypted token to store client-side
// - `email` - Email address of the connected account
// - `state` - Your original state parameter (for CSRF verification)
//
// **On error:**
//
// - `error` - Error code (e.g., `access_denied`, `token_exchange_failed`)
// - `state` - Your original state parameter
//
// **Store the `inbox_token` client-side** and use it for all subsequent inbox API
// calls.
func (r *InboxService) ConnectEmail(ctx context.Context, body InboxConnectEmailParams, opts ...option.RequestOption) (res *InboxConnectEmailResponse, err error) {
opts = slices.Concat(r.Options, opts)
path := "v4/inbox/connect"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
return res, err
}
// Revoke email access and invalidate the token.
//
// This calls the provider's token revocation API (e.g., Google's revoke endpoint)
// to ensure the user's consent is properly removed.
//
// After calling this, the `inbox_token` becomes unusable.
func (r *InboxService) DisconnectEmail(ctx context.Context, body InboxDisconnectEmailParams, opts ...option.RequestOption) (res *InboxDisconnectEmailResponse, err error) {
if !param.IsOmitted(body.XInboxToken) {
opts = append(opts, option.WithHeader("x-inbox-token", fmt.Sprintf("%v", body.XInboxToken)))
}
opts = slices.Concat(r.Options, opts)
path := "v4/inbox/disconnect"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
return res, err
}
// Search the user's email inbox for CAS files from known senders (CAMS, KFintech,
// CDSL, NSDL).
//
// Files are uploaded to temporary cloud storage. **URLs expire in 24 hours.**
//
// Optionally filter by CAS provider and date range.
//
// **Billing:** 0.2 credits per request (charged regardless of success or number of
// files found).
func (r *InboxService) ListCasFiles(ctx context.Context, params InboxListCasFilesParams, opts ...option.RequestOption) (res *InboxListCasFilesResponse, err error) {
if !param.IsOmitted(params.XInboxToken) {
opts = append(opts, option.WithHeader("x-inbox-token", fmt.Sprintf("%v", params.XInboxToken)))
}
opts = slices.Concat(r.Options, opts)
path := "v4/inbox/cas"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
return res, err
}
type InboxCheckConnectionStatusResponse struct {
// Whether the token is valid and usable
Connected bool `json:"connected"`
// Email address of the connected account
Email string `json:"email" format:"email"`
Provider string `json:"provider"`
Status string `json:"status"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Connected respjson.Field
Email respjson.Field
Provider respjson.Field
Status respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
// Returns the unmodified JSON received from the API
func (r InboxCheckConnectionStatusResponse) RawJSON() string { return r.JSON.raw }
func (r *InboxCheckConnectionStatusResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
type InboxConnectEmailResponse struct {
// Seconds until the OAuth URL expires (typically 10 minutes)
ExpiresIn int64 `json:"expires_in"`
// Redirect user to this URL to start OAuth flow
OAuthURL string `json:"oauth_url" format:"uri"`
Status string `json:"status"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
ExpiresIn respjson.Field
OAuthURL respjson.Field
Status respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
// Returns the unmodified JSON received from the API
func (r InboxConnectEmailResponse) RawJSON() string { return r.JSON.raw }
func (r *InboxConnectEmailResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
type InboxDisconnectEmailResponse struct {
Msg string `json:"msg"`
Status string `json:"status"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Msg respjson.Field
Status respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
// Returns the unmodified JSON received from the API
func (r InboxDisconnectEmailResponse) RawJSON() string { return r.JSON.raw }
func (r *InboxDisconnectEmailResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
type InboxListCasFilesResponse struct {
// Number of CAS files found
Count int64 `json:"count"`
Files []InboxListCasFilesResponseFile `json:"files"`
Status string `json:"status"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Count respjson.Field
Files respjson.Field
Status respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
// Returns the unmodified JSON received from the API
func (r InboxListCasFilesResponse) RawJSON() string { return r.JSON.raw }
func (r *InboxListCasFilesResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
// A CAS file found in the user's email inbox
type InboxListCasFilesResponseFile struct {
// Detected CAS provider based on sender email
//
// Any of "cdsl", "nsdl", "cams", "kfintech".
CasType string `json:"cas_type"`
// URL expiration time in seconds (default 86400 = 24 hours)
ExpiresIn int64 `json:"expires_in"`
// Standardized filename (provider_YYYYMMDD_uniqueid.pdf)
Filename string `json:"filename"`
// Date the email was received
MessageDate time.Time `json:"message_date" format:"date"`
// Unique identifier for the email message (use for subsequent API calls)
MessageID string `json:"message_id"`
// Original attachment filename from the email
OriginalFilename string `json:"original_filename"`
// Email address of the CAS authority (CDSL, NSDL, CAMS, or KFintech) who
// originally sent this statement
SenderEmail string `json:"sender_email" format:"email"`
// File size in bytes
Size int64 `json:"size"`
// Direct download URL (presigned, expires based on expires_in)
URL string `json:"url" format:"uri"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
CasType respjson.Field
ExpiresIn respjson.Field
Filename respjson.Field
MessageDate respjson.Field
MessageID respjson.Field
OriginalFilename respjson.Field
SenderEmail respjson.Field
Size respjson.Field
URL respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
// Returns the unmodified JSON received from the API
func (r InboxListCasFilesResponseFile) RawJSON() string { return r.JSON.raw }
func (r *InboxListCasFilesResponseFile) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
type InboxCheckConnectionStatusParams struct {
XInboxToken string `header:"x-inbox-token" api:"required" json:"-"`
paramObj
}
type InboxConnectEmailParams struct {
// Your callback URL to receive the inbox_token (must be http or https)
RedirectUri string `json:"redirect_uri" api:"required" format:"uri"`
// State parameter for CSRF protection (returned in redirect)
State param.Opt[string] `json:"state,omitzero"`
paramObj
}
func (r InboxConnectEmailParams) MarshalJSON() (data []byte, err error) {
type shadow InboxConnectEmailParams
return param.MarshalObject(r, (*shadow)(&r))
}
func (r *InboxConnectEmailParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
type InboxDisconnectEmailParams struct {
XInboxToken string `header:"x-inbox-token" api:"required" json:"-"`
paramObj
}
type InboxListCasFilesParams struct {
XInboxToken string `header:"x-inbox-token" api:"required" json:"-"`
// End date in ISO format (YYYY-MM-DD). Defaults to today.
EndDate param.Opt[time.Time] `json:"end_date,omitzero" format:"date"`
// Start date in ISO format (YYYY-MM-DD). Defaults to 30 days ago.
StartDate param.Opt[time.Time] `json:"start_date,omitzero" format:"date"`
// Filter by CAS provider(s):
//
// - `cdsl` → eCAS@cdslstatement.com
// - `nsdl` → NSDL-CAS@nsdl.co.in
// - `cams` → donotreply@camsonline.com
// - `kfintech` → samfS@kfintech.com
//
// Any of "cdsl", "nsdl", "cams", "kfintech".
CasTypes []string `json:"cas_types,omitzero"`
paramObj
}
func (r InboxListCasFilesParams) MarshalJSON() (data []byte, err error) {
type shadow InboxListCasFilesParams
return param.MarshalObject(r, (*shadow)(&r))
}
func (r *InboxListCasFilesParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}