Compare commits

...

7 commits
v0.2 ... main

Author SHA1 Message Date
TheWanderingCrow
586e336cb8 chore: release v2.0 2025-12-30 22:11:21 -05:00
TheWanderingCrow
1c1b2a3a1d fix!: SMTP now works properly in non-dev environments 2025-12-30 21:50:16 -05:00
TheWanderingCrow
43d4e6caee chore: update sha256 2025-12-30 21:21:02 -05:00
TheWanderingCrow
00104dc59a docs: fix syntax error in README.md 2025-12-27 11:04:28 -05:00
TheWanderingCrow
ae765605d9 chore: release v1.0 2025-12-27 10:57:43 -05:00
TheWanderingCrow
6eb0beb355 add support for encryption key protected budget files 2025-12-27 10:45:49 -05:00
TheWanderingCrow
700659ff60 fix: make module work and add instructions for using 2025-12-26 17:23:31 -05:00
4 changed files with 74 additions and 59 deletions

View file

@ -12,8 +12,10 @@ inputs.actualbudget-report.url = "git+https://git.wanderingcrow.net/TheWandering
Then in your configuration (using sops-nix, you will need to adjust it if you use agenix or alternatives): Then in your configuration (using sops-nix, you will need to adjust it if you use agenix or alternatives):
```nix ```nix
nixpkgs.overlays = [ inputs.actualbudget-report.overlays.default ];
imports = [ imports = [
inputs.actualbudget-report.nixosModules.default; inputs.actualbudget-report.nixosModules.default
]; ];
# Fill out all the following environment variables for the service # Fill out all the following environment variables for the service
@ -25,6 +27,7 @@ sops.templates."actualbudget-report-env".content = ''
SMTP_PASSWORD= SMTP_PASSWORD=
SMTP_HOST= SMTP_HOST=
SMTP_RECIPIENTS= SMTP_RECIPIENTS=
BUDGET_ENCRYPTION_KEY=
''; '';
services.actualbudget-report = { services.actualbudget-report = {

View file

@ -7,44 +7,52 @@
}; };
outputs = outputs =
inputs@{ flake-parts, ... }: inputs@{
flake-parts.lib.mkFlake { inherit inputs; } { self,
systems = [ flake-parts,
"x86_64-linux" ...
"aarch64-linux" }:
"aarch64-darwin" flake-parts.lib.mkFlake
"x86_64-darwin" {
]; inherit inputs;
flake.nixosModules = { }
default = ./modules/actualbudget-report; {
}; imports = [ inputs.flake-parts.flakeModules.easyOverlay ];
perSystem = systems = [
{ "x86_64-linux"
config, "aarch64-linux"
self', "aarch64-darwin"
inputs', "x86_64-darwin"
pkgs, ];
system, flake.nixosModules.default = ./modules/actualbudget-report;
... perSystem =
}: {
{ config,
packages.default = pkgs.buildGoModule { self',
name = "actualbudget-report"; inputs',
src = pkgs.fetchFromGitea { pkgs,
domain = "git.wanderingcrow.net"; system,
owner = "TheWanderingCrow"; ...
repo = "actualbudget-report"; }:
rev = "v0.1"; {
hash = "sha256-1Z3+Efx0MCsZhfz49nKsdaWgyVt9+7kekwgfQyaYUxQ="; overlayAttrs = { inherit (config.packages) actualbudget-report; };
packages.actualbudget-report = pkgs.buildGoModule {
name = "actualbudget-report";
src = pkgs.fetchFromGitea {
domain = "git.wanderingcrow.net";
owner = "TheWanderingCrow";
repo = "actualbudget-report";
rev = "v2.0";
hash = "sha256-H+pA9dFsP5QQ3W32NEU1TWYiOiti53jnzN3Bnq+QJ5Q=";
};
vendorHash = "sha256-NHTKwUSIbNCUco88JbHOo3gt6S37ggee+LWNbHaRGEs=";
};
devShells.default = pkgs.mkShell {
ENVIRONMENT = "dev";
nativeBuildInputs = with pkgs; [
devenv
];
}; };
vendorHash = "sha256-NHTKwUSIbNCUco88JbHOo3gt6S37ggee+LWNbHaRGEs=";
}; };
devShells.default = pkgs.mkShell { };
ENVIRONMENT = "dev";
nativeBuildInputs = with pkgs; [
devenv
];
};
};
};
} }

32
main.go
View file

@ -32,10 +32,11 @@ import (
) )
type BudgetClient struct { type BudgetClient struct {
baseUrl string baseUrl string
apiKey string apiKey string
syncId string syncId string
fullUrl string fullUrl string
encryptionKey string
} }
type BudgetMonthsResponse struct { type BudgetMonthsResponse struct {
@ -73,9 +74,12 @@ type BudgetMonthsResponse struct {
} `json:"data"` } `json:"data"`
} }
func CreateBudgetClient(baseUrl string, apiKey string, syncId string) *BudgetClient { // Create budget client, you may pass empty strings to optional parameters
// Required: baseUrl, apiKey, syncId
// Optional: encryptionKey
func CreateBudgetClient(baseUrl string, apiKey string, syncId string, encryptionKey string) *BudgetClient {
fullUrl := baseUrl + "/v1/budgets/" + syncId fullUrl := baseUrl + "/v1/budgets/" + syncId
client := BudgetClient{baseUrl, apiKey, syncId, fullUrl} client := BudgetClient{baseUrl, apiKey, syncId, fullUrl, encryptionKey}
return &client return &client
} }
@ -111,7 +115,9 @@ func (b BudgetClient) GetBudgetMonths() *BudgetMonthsResponse {
currentTime := time.Now() currentTime := time.Now()
year, month := currentTime.Year(), int(currentTime.Month()) year, month := currentTime.Year(), int(currentTime.Month())
budgetMonth := fmt.Sprintf("%v-%v", year, month) budgetMonth := fmt.Sprintf("%v-%v", year, month)
resp := b.callApi("GET", "/months/"+budgetMonth, nil) resp := b.callApi("GET", "/months/"+budgetMonth, map[string]string{
"budget-encryption-password": b.encryptionKey,
})
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
log.Fatal("GetBudgetAmounts failed with: " + string(resp.Status)) log.Fatal("GetBudgetAmounts failed with: " + string(resp.Status))
@ -139,11 +145,13 @@ 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 encryptionKey = os.Getenv("BUDGET_ENCRYPTION_KEY")
var smtpUsername = os.Getenv("SMTP_USERNAME") var smtpUsername = os.Getenv("SMTP_USERNAME")
var smtpPassword = os.Getenv("SMTP_PASSWORD") var smtpPassword = os.Getenv("SMTP_PASSWORD")
var smtpHost = os.Getenv("SMTP_HOST") var smtpHost = os.Getenv("SMTP_HOST")
var smtpPort = os.Getenv("SMTP_PORT")
var smtpRecipients = os.Getenv("SMTP_RECIPIENTS") var smtpRecipients = os.Getenv("SMTP_RECIPIENTS")
client := CreateBudgetClient(baseUrl, apiKey, syncId) client := CreateBudgetClient(baseUrl, apiKey, syncId, encryptionKey)
if !client.BankSync() { if !client.BankSync() {
log.Println("Bank Sync failed, information may not be up to date") log.Println("Bank Sync failed, information may not be up to date")
} }
@ -177,12 +185,8 @@ func main() {
message := []byte(subject + mime + body + categories.String()) message := []byte(subject + mime + body + categories.String())
var auth smtp.Auth var auth smtp.Auth
if os.Getenv("ENVIRONMENT") == "dev" { auth = smtp.PlainAuth("", smtpUsername, smtpPassword, smtpHost)
auth = nil err := smtp.SendMail(smtpHost+":"+smtpPort, auth, smtpUsername, strings.Split(smtpRecipients, ","), []byte(message))
} else {
auth = smtp.PlainAuth("", smtpUsername, smtpPassword, smtpHost)
}
err := smtp.SendMail(smtpHost, auth, smtpUsername, strings.Split(smtpRecipients, ","), []byte(message))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View file

@ -1,8 +1,8 @@
{ {
pkgs,
config, config,
options, options,
lib, lib,
pkgs,
... ...
}: }:
let let
@ -10,8 +10,8 @@ let
opt = options.services.actualbudget-report; opt = options.services.actualbudget-report;
inherit (lib) inherit (lib)
mkEnableOption mkEnableOption
mkOption
mkPackageOption mkPackageOption
mkOption
mkIf mkIf
types types
; ;
@ -20,12 +20,12 @@ in
options = { options = {
services.actualbudget-report = { services.actualbudget-report = {
enable = mkEnableOption "Actualbudget email reports"; enable = mkEnableOption "Actualbudget email reports";
package = mkPackageOption pkgs.default; interval = mkOption {
interval = {
type = types.str; type = types.str;
default = "Sun 12:00:00"; default = "Sun 12:00:00";
description = "systemd-timer OnCalendar legal string for sending reports."; description = "systemd-timer OnCalendar legal string for sending reports.";
}; };
package = mkPackageOption pkgs "actualbudget-report" { };
environmentFile = mkOption { environmentFile = mkOption {
type = types.path; type = types.path;
default = ""; default = "";
@ -39,11 +39,11 @@ in
description = "Actualbudget report sender service"; description = "Actualbudget report sender service";
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
ExecStart = "${cfg.package}/bin/actualbudget-report"; ExecStart = "${pkgs.actualbudget-report}/bin/actualbudget-report";
EnvironmentFile = cfg.environmentFile; EnvironmentFile = cfg.environmentFile;
}; };
}; };
systemd.timers.flamesite-backup = { systemd.timers.actualbudget-report = {
enable = true; enable = true;
wantedBy = [ "timers.target" ]; wantedBy = [ "timers.target" ];
timerConfig = { timerConfig = {