feat!: Finalize code
This commit is contained in:
parent
006f301484
commit
80f5b39961
1 changed files with 116 additions and 5 deletions
121
src/main.go
121
src/main.go
|
|
@ -1,10 +1,17 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/smtp"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BudgetClient struct {
|
type BudgetClient struct {
|
||||||
|
|
@ -14,6 +21,41 @@ type BudgetClient struct {
|
||||||
fullUrl string
|
fullUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BudgetMonthsResponse struct {
|
||||||
|
Data struct {
|
||||||
|
Month string `json:"month"`
|
||||||
|
IncomeAvailable int `json:"incomeAvailable"`
|
||||||
|
LastMonthOverspent int `json:"lastMonthOverspent"`
|
||||||
|
ForNextMonth int `json:"forNextMonth"`
|
||||||
|
TotalBudgeted int `json:"totalBudgeted"`
|
||||||
|
ToBudget int `json:"toBudget"`
|
||||||
|
FromLastMonth int `json:"fromLastMonth"`
|
||||||
|
TotalIncome int `json:"totalIncome"`
|
||||||
|
TotalSpent int `json:"totalSpent"`
|
||||||
|
TotalBalance int `json:"totalBalance"`
|
||||||
|
CategoryGroups []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
IsIncome bool `json:"is_income"`
|
||||||
|
Hidden bool `json:"hidden"`
|
||||||
|
Budgeted int `json:"budgeted"`
|
||||||
|
Spent int `json:"spent"`
|
||||||
|
Balance int `json:"balance"`
|
||||||
|
Categories []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
IsIncome bool `json:"is_income"`
|
||||||
|
Hidden bool `json:"hidden"`
|
||||||
|
GroupID string `json:"group_id"`
|
||||||
|
Budgeted int `json:"budgeted"`
|
||||||
|
Spent int `json:"spent"`
|
||||||
|
Balance int `json:"balance"`
|
||||||
|
Carryover bool `json:"carryover"`
|
||||||
|
} `json:"categories"`
|
||||||
|
} `json:"categoryGroups"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
func CreateBudgetClient(baseUrl string, apiKey string, syncId string) *BudgetClient {
|
func CreateBudgetClient(baseUrl string, apiKey string, syncId string) *BudgetClient {
|
||||||
fullUrl := baseUrl + "/v1/budgets/" + syncId
|
fullUrl := baseUrl + "/v1/budgets/" + syncId
|
||||||
client := BudgetClient{baseUrl, apiKey, syncId, fullUrl}
|
client := BudgetClient{baseUrl, apiKey, syncId, fullUrl}
|
||||||
|
|
@ -25,7 +67,7 @@ func CreateBudgetClient(baseUrl string, apiKey string, syncId string) *BudgetCli
|
||||||
// method is POST, GET, ect
|
// method is POST, GET, ect
|
||||||
// route is the route to call with a leading / ex. /accounts/banksync
|
// route is the route to call with a leading / ex. /accounts/banksync
|
||||||
// headers is a map of strings expecting "header" "value"
|
// headers is a map of strings expecting "header" "value"
|
||||||
func (b BudgetClient) callApi(method string, route string, headers map[string]string) bool {
|
func (b BudgetClient) callApi(method string, route string, headers map[string]string) *http.Response {
|
||||||
var httpClient http.Client
|
var httpClient http.Client
|
||||||
req, err := http.NewRequest(method, b.fullUrl+route, http.NoBody)
|
req, err := http.NewRequest(method, b.fullUrl+route, http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -39,12 +81,35 @@ func (b BudgetClient) callApi(method string, route string, headers map[string]st
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Println(resp)
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers a bank sync, returns true if successful
|
||||||
|
func (b BudgetClient) BankSync() bool {
|
||||||
|
resp := b.callApi("POST", "/accounts/banksync", nil)
|
||||||
return resp.StatusCode == http.StatusOK
|
return resp.StatusCode == http.StatusOK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BudgetClient) BankSync() bool {
|
func (b BudgetClient) GetBudgetMonths() *BudgetMonthsResponse {
|
||||||
return b.callApi("POST", "/accounts/banksync", nil)
|
currentTime := time.Now()
|
||||||
|
year, month := currentTime.Year(), int(currentTime.Month())
|
||||||
|
budgetMonth := fmt.Sprintf("%v-%v", year, month)
|
||||||
|
resp := b.callApi("GET", "/months/"+budgetMonth, nil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
log.Fatal("GetBudgetAmounts failed with: " + string(resp.Status))
|
||||||
|
}
|
||||||
|
var data bytes.Buffer
|
||||||
|
|
||||||
|
_, err := io.Copy(&data, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var budgetMonths BudgetMonthsResponse
|
||||||
|
err = json.Unmarshal(data.Bytes(), &budgetMonths)
|
||||||
|
return &budgetMonths
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -57,6 +122,52 @@ func main() {
|
||||||
var baseUrl = os.Getenv("BASE_URL")
|
var baseUrl = os.Getenv("BASE_URL")
|
||||||
var apiKey = os.Getenv("API_KEY")
|
var apiKey = os.Getenv("API_KEY")
|
||||||
var syncId = os.Getenv("SYNC_ID")
|
var syncId = os.Getenv("SYNC_ID")
|
||||||
|
var smtpUsername = os.Getenv("SMTP_USERNAME")
|
||||||
|
var smtpPassword = os.Getenv("SMTP_PASSWORD")
|
||||||
|
var smtpHost = os.Getenv("SMTP_HOST")
|
||||||
|
var smtpRecipients = os.Getenv("SMTP_RECIPIENTS")
|
||||||
client := CreateBudgetClient(baseUrl, apiKey, syncId)
|
client := CreateBudgetClient(baseUrl, apiKey, syncId)
|
||||||
client.BankSync()
|
//if !client.BankSync() {
|
||||||
|
// log.Println("Bank Sync failed, information may not be up to date")
|
||||||
|
//}
|
||||||
|
budgetMonths := client.GetBudgetMonths()
|
||||||
|
|
||||||
|
subject := "Subject: Budget Report\n"
|
||||||
|
mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
|
||||||
|
const bodyTemplate = `
|
||||||
|
<p>Good day,</p>
|
||||||
|
<p>Your unallocated budget total as of %s: <b>$%v</b></p>
|
||||||
|
|
||||||
|
<p>Category breakdown:</p>
|
||||||
|
`
|
||||||
|
var categories strings.Builder
|
||||||
|
|
||||||
|
for _, v := range budgetMonths.Data.CategoryGroups {
|
||||||
|
for _, v2 := range v.Categories {
|
||||||
|
if !v2.IsIncome {
|
||||||
|
bal := float32(v2.Balance)
|
||||||
|
bal /= 100
|
||||||
|
fmt.Fprintf(&categories, "<p>%v: <b>$%v</b></p>", v2.Name, bal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
categories.Write([]byte("<p>This is an automated report generated by <a href=\"https://git.wanderingcrow.net/TheWanderingCrow/actualbudget-report\">actualbudget-report</a>"))
|
||||||
|
|
||||||
|
currentTime := time.Now()
|
||||||
|
toBudget := float32(budgetMonths.Data.ToBudget)
|
||||||
|
toBudget /= 100
|
||||||
|
body := fmt.Sprintf(bodyTemplate, currentTime.Format(time.RFC850), toBudget)
|
||||||
|
message := []byte(subject + mime + body + categories.String())
|
||||||
|
|
||||||
|
var auth smtp.Auth
|
||||||
|
if os.Getenv("ENVIRONMENT") == "dev" {
|
||||||
|
auth = nil
|
||||||
|
} else {
|
||||||
|
auth = smtp.PlainAuth("", smtpUsername, smtpPassword, smtpHost)
|
||||||
|
}
|
||||||
|
err := smtp.SendMail(smtpHost, auth, smtpUsername, []string{smtpRecipients}, []byte(message))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue