oneandone-billing-mailer/cmd/test/main.go

214 lines
5.4 KiB
Go

package main
import (
"context"
"flag"
"io"
"mime"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/api"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/appcontext"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/auth"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/auth/authcache"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/auth/authcache/fileauthcache"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/backend"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/environment"
"github.com/go-logr/logr"
"github.com/go-logr/zapr"
"go.uber.org/zap"
"golang.org/x/oauth2"
)
const (
// webviewDebug toggles the debug mode in the Webview library.
webviewDebug = false
// apiDebug toggles the debug mode in the OpenAPI client.
apiDebug = false
)
// dateFormat is the format used to pass dates to the 1&1 API
const dateFormat = "2006-01-02"
// main is the main entrypoint.
func main() {
ctx := context.Background()
// load logger
zapLogger, err := zap.NewDevelopment()
if err != nil {
os.Stderr.WriteString("Could not initialize zap logger\n")
os.Exit(1)
return
}
generalLog := zapr.NewLogger(zapLogger)
ctx = logr.NewContext(ctx, generalLog)
log := generalLog.WithName("app")
// parse cmdline
flag.Parse()
// initialize oauth stuff for API
oauth, err := auth.NewOAuthFromEnvironment(ctx)
if err != nil {
log.Error(err, "Failed to initialize central login helper")
return
}
// Try and get an initial token first
tokenCache := fileauthcache.NewFileAuthCache("token.json")
token, err := tokenCache.Fetch()
if err != nil {
log.Error(err, "Failed to fetch token from cache")
return
}
if token == nil {
// We need to fetch an initial token
tokenSource, err := oauth.TokenSource(nil, requestUserConsentFunc(ctx))
if err != nil {
log.Error(err, "Failed to set up OAuth token source")
return
}
cacheTokenSource := authcache.NewCacheTokenSource(ctx, tokenCache, tokenSource)
token, err = cacheTokenSource.Token()
if err != nil {
log.Error(err, "Failed to fetch initial token")
return
}
}
// Set up new token source only for refreshing
tokenSource, err := oauth.TokenSource(token, nil)
if err != nil {
log.Error(err, "Failed to set up OAuth token source")
return
}
cacheTokenSource := authcache.NewCacheTokenSource(ctx, tokenCache, tokenSource)
reuseTokenSource := oauth2.ReuseTokenSource(token, cacheTokenSource)
client := oauth2.NewClient(ctx, reuseTokenSource)
client.Transport = backend.BackendRequestTransport(client.Transport)
// MSSA invoice requests from here
appctx, err := appcontext.GetEnvironmentContext()
if err != nil {
log.Error(err, "Failed to fetch app env context")
return
}
mssaBaseURL, err := appctx.MSSA.BaseURL()
if err != nil {
log.Error(err, "Failed to parse MSSA base URL")
return
}
auth := context.WithValue(ctx, api.ContextOAuth2, reuseTokenSource)
apiConfig := api.NewConfiguration()
apiConfig.HTTPClient = client
apiConfig.Debug = apiDebug
apiConfig.UserAgent = environment.UserAgent()
apiClient := api.NewAPIClient(apiConfig)
now := time.Now()
thisMonthStartDate := now.
// go to first day of this month
AddDate(0, 0, 1-now.Day())
nextMonthStartDate := thisMonthStartDate.
// add 1 month
AddDate(0, 1, 0)
apiReq := apiClient.InvoicesApi.GetInvoicesInInterval(auth,
thisMonthStartDate.Format(dateFormat),
nextMonthStartDate.Format(dateFormat)).
PerPage(1)
apiResp, resp, err := apiReq.Page(1).Execute()
if err != nil {
panic(err)
}
if resp.StatusCode != http.StatusOK {
panic(resp.Status)
}
for _, invoice := range apiResp.GetInvoice() {
// skip entries without invoice document
doc := invoice.Links.InvoiceDocument
if doc == nil {
continue
}
ext := ".pdf"
if doc.Type != nil {
exts, err := mime.ExtensionsByType(*doc.Type)
if err != nil {
log.V(1).Error(err, "Failed to fetch extensions for type",
"type", *doc.Type)
} else if len(exts) > 0 {
ext = exts[0]
}
}
// make sure extension starts with dot
if !strings.HasPrefix(ext, ".") {
ext = "." + ext
}
title := "Rechnung"
if doc.Title != nil {
title = *doc.Title
}
fileName := filepath.Clean(title) + ext
u, err := url.Parse(doc.Href)
if err != nil {
log.V(1).Error(err, "Failed to parse invoice document hyperlink reference, skipping",
"url", doc.Href)
continue
}
u = mssaBaseURL.ResolveReference(u)
// open PDF on server
resp, err := apiClient.GetConfig().HTTPClient.Get(u.String())
if err != nil {
log.Error(err, "Invoice PDF download request failed, skipping",
"fileName", fileName)
continue
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
log.Error(err, "Unexpected status code for invoice PDF download request, skipping",
"fileName", fileName,
"statusCode", resp.StatusCode)
continue
}
// write PDF to file as we download
f, err := os.Create(fileName)
if err != nil {
resp.Body.Close()
log.Error(err, "Could not create invoice PDF",
"fileName", fileName)
continue
}
_, err = io.Copy(f, resp.Body)
resp.Body.Close()
if err != nil {
os.Remove(f.Name())
log.Error(err, "Could not write to invoice PDF",
"fileName", fileName)
}
err = f.Close()
if err != nil {
os.Remove(f.Name())
log.Error(err, "Could not complete writing to invoice PDF",
"fileName", fileName)
}
}
}