Commit 37960dc6 authored by Sybren A. Stüvel's avatar Sybren A. Stüvel

Added 'afromen' proggy

parent b81f61ec
bunq_credentials.yaml
bunq_key_private.pem
/afromen/afromen
OUT := afromen
PKG := gitlab.com/dr.sybren/bunqapi/afromen
VERSION := $(shell git describe --tags --dirty --always)
PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/)
STATIC_OUT := ${OUT}-v${VERSION}
PACKAGE_PATH := dist/${OUT}-${VERSION}
ifndef PACKAGE_PATH
# ${PACKAGE_PATH} is used in 'rm' commands, so it's important to check.
$(error PACKAGE_PATH is not set)
endif
all: binary
binary:
go build -i -v -o ${OUT} -ldflags="-X main.applicationVersion=${VERSION}" ${PKG}
install:
go install -i -v -ldflags="-X main.applicationVersion=${VERSION}" ${PKG}
version:
@echo "Package: ${PKG}"
@echo "Version: ${VERSION}"
test:
go test -short ${PKG_LIST}
vet:
@go vet ${PKG_LIST}
lint:
@for file in ${GO_FILES} ; do \
golint $$file ; \
done
run: binary
./${OUT}
clean:
@go clean -i -x
rm -f ${OUT}-v*
static: vet lint
go build -i -v -o ${STATIC_OUT} -tags netgo -ldflags="-extldflags \"-static\" -w -s -X main.applicationVersion=${VERSION}" ${PKG}
.gitlabAccessToken:
$(error gitlabAccessToken does not exist, visit Visit https://gitlab.com/profile/personal_access_tokens, create a Personal Access Token with API access then save it to the file .gitlabAccessToken)
release: .gitlabAccessToken package
rsync ${PACKAGE_PATH}* stuvelfoto@stuvel.eu:downloads/skyfill/ -va
go run release/release.go -version ${VERSION} -fileglob ${PACKAGE_PATH}\*
package:
@$(MAKE) _prepare_package
@$(MAKE) _package_linux
@$(MAKE) _package_windows
@$(MAKE) _package_darwin
@$(MAKE) _finish_package
package_linux:
@$(MAKE) _prepare_package
@$(MAKE) _package_linux
@$(MAKE) _finish_package
package_windows:
@$(MAKE) _prepare_package
@$(MAKE) _package_windows
@$(MAKE) _finish_package
package_darwin:
@$(MAKE) _prepare_package
@$(MAKE) _package_darwin
@$(MAKE) _finish_package
_package_linux:
@$(MAKE) --no-print-directory GOOS=linux MONGOOS=linux GOARCH=amd64 STATIC_OUT=${PACKAGE_PATH}/${OUT} _package_tar
_package_windows:
@$(MAKE) --no-print-directory GOOS=windows MONGOOS=windows GOARCH=amd64 STATIC_OUT=${PACKAGE_PATH}/${OUT}.exe _package_zip
_package_darwin:
@$(MAKE) --no-print-directory GOOS=darwin MONGOOS=osx GOARCH=amd64 STATIC_OUT=${PACKAGE_PATH}/${OUT} _package_zip
_prepare_package:
rm -rf ${PACKAGE_PATH}
mkdir -p ${PACKAGE_PATH}
cp -ua README.md LICENSE demo ${PACKAGE_PATH}/
_finish_package:
rm -r ${PACKAGE_PATH}
rm -f ${PACKAGE_PATH}.sha256
sha256sum ${PACKAGE_PATH}* | tee ${PACKAGE_PATH}.sha256
_package_tar: static
tar -C $(dir ${PACKAGE_PATH}) -zcf $(PWD)/${PACKAGE_PATH}-${GOOS}.tar.gz $(notdir ${PACKAGE_PATH})
rm ${STATIC_OUT}
_package_zip: static
cd $(dir ${PACKAGE_PATH}) && zip -9 -r -q $(notdir ${PACKAGE_PATH})-${GOOS}.zip $(notdir ${PACKAGE_PATH})
rm ${STATIC_OUT}
.PHONY: run server version static vet lint deploy package release
/* (c) 2019 dr. Sybren A. Stüvel
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package main
import (
"flag"
"fmt"
"log"
"github.com/sirupsen/logrus"
"gitlab.com/dr.sybren/bunqapi"
)
const (
applicationName = "Afromen"
currency = "EUR"
)
var applicationVersion = "set-during-build"
var cliArgs struct {
quiet bool
debug bool
version bool
transferFromAccount int
transferToAccount int
threshold int
}
func parseCliArgs() {
flag.BoolVar(&cliArgs.quiet, "quiet", false, "Disable info-level logging.")
flag.BoolVar(&cliArgs.debug, "debug", false, "Enable debug-level logging.")
flag.BoolVar(&cliArgs.version, "version", false, "Show the application version and exit.")
flag.IntVar(&cliArgs.transferFromAccount, "from", 0, "Account ID to transfer money from.")
flag.IntVar(&cliArgs.transferToAccount, "to", 0, "Account ID to transfer money to.")
flag.IntVar(&cliArgs.threshold, "threshold", 0,
fmt.Sprintf("The amount (in entire %s) by which the 'from' account balance is over this threshold is transferred.", currency))
flag.Parse()
}
func configLogging() {
logfmt := &logrus.TextFormatter{
FullTimestamp: true,
}
// Only log the warning severity or above by default.
var level logrus.Level
switch {
case cliArgs.debug:
level = logrus.DebugLevel
case cliArgs.quiet:
level = logrus.WarnLevel
default:
level = logrus.InfoLevel
}
logrus.SetLevel(level)
logrus.SetFormatter(logfmt)
log.SetOutput(logrus.StandardLogger().Writer())
bunqapi.LogLevel(logrus.GetLevel())
bunqapi.LogFormatter(logfmt)
}
func main() {
parseCliArgs()
configLogging()
if cliArgs.version {
logrus.WithField("version", applicationVersion).Info(applicationName)
return
}
logrus.WithField("version", applicationVersion).Infof("starting %s", applicationName)
creds := bunqapi.LoadCredentials()
logrus.WithField("apiMode", creds.APIMode).Debug("loaded credentials")
client := bunqapi.NewClient(creds)
client.CheckInstallation()
client.CheckDeviceServer("je moeder", []string{})
client.SessionStart()
defer client.SessionStop()
if cliArgs.transferFromAccount == 0 || cliArgs.transferToAccount == 0 || cliArgs.threshold == 0 {
logrus.Warn("to or from account ID or threshold not given, going to list bank accounts")
listBankAccounts(client)
return
}
threshold := bunqapi.NewAmount(currency, cliArgs.threshold*100)
afromen(client, threshold)
}
func listBankAccounts(client *bunqapi.Client) {
accounts := client.GetMonetaryAccountBankList()
for len(accounts) < 2 {
logrus.Warning("not enough bank accounts, creating one")
bankAccount := bunqapi.MonetaryAccountBank{
Currency: "EUR",
}
client.CreateMonetaryAccountBank(bankAccount)
accounts = client.GetMonetaryAccountBankList()
}
logrus.WithField("numAccounts", len(accounts)).Info("enough bank accounts found")
for _, account := range accounts {
logrus.WithFields(account.AliasFields()).WithFields(logrus.Fields{
"accountID": account.ID,
"balance": account.Balance.String(),
}).Info("account balance")
}
}
func afromen(client *bunqapi.Client, threshold bunqapi.Amount) {
fromAccount, err := client.GetMonetaryAccountBank(cliArgs.transferFromAccount)
if err != nil {
logrus.WithFields(logrus.Fields{
"accountID": cliArgs.transferFromAccount,
logrus.ErrorKey: err,
}).Fatal("unable to find source account")
}
logrus.WithFields(fromAccount.AliasFields()).WithFields(logrus.Fields{
"accountID": fromAccount.ID,
"balance": fromAccount.Balance.String(),
}).Info("source account")
toAccount, err := client.GetMonetaryAccountBank(cliArgs.transferToAccount)
if err != nil {
logrus.WithFields(logrus.Fields{
"accountID": cliArgs.transferFromAccount,
logrus.ErrorKey: err,
}).Fatal("unable to find target account")
}
logrus.WithFields(toAccount.AliasFields()).WithFields(logrus.Fields{
"accountID": toAccount.ID,
"balance": toAccount.Balance.String(),
}).Info("destination account")
logger := logrus.WithField("threshold", threshold.String())
toTransfer, err := fromAccount.Balance.Sub(threshold)
if err != nil {
logger.WithError(err).Fatal("error computing amount to transfer")
}
if toTransfer.IsNonPositive() {
logger.WithField("accountBalance", fromAccount.Balance.String()).Info("balance < threshold, not transferring")
return
}
logger = logger.WithField("toTransfer", toTransfer.String())
logger.Info("going to transfer money")
toAlias := toAccount.IBANAlias()
payment := bunqapi.Payment{
Amount: &toTransfer,
Description: "automatisch afromen",
CounterpartyAlias: &bunqapi.LabelMonetaryAccount{
Type: toAlias.Type,
Value: toAlias.Value,
Name: "je moeder",
},
}
client.CreatePayment(fromAccount.ID, payment)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment