Skip to content

Commit

Permalink
Merge pull request #8 from guitmz/block-cards
Browse files Browse the repository at this point in the history
Block/Unblock cards and goreleaser
  • Loading branch information
guitmz authored Jul 24, 2018
2 parents f369096 + 63de065 commit 2a6dc4b
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 22 deletions.
43 changes: 43 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
builds:
- env:
- CGO_ENABLED=0
main: ./cmd/n26
binary: n26
goos:
- linux
- darwin
- windows
- freebsd
goarch:
- amd64
archive:
name_template: "{{ .ProjectName }}-cli-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
format: zip
files:
- none*
checksum:
name_template: "checksums.txt"
release:
github:
owner: guitmz
name: n26
name_template: "{{.Version}}"
changelog:
sort: asc
filters:
exclude:
- "typo"
- "^docs:"
- "^test:"
brew:
github:
owner: guitmz
name: homebrew-tools

homepage: "https://github.com/guitmz/n26"
description: "CLI tool for N26 Bank"
test: |
system "#{bin}/n26", "--version"
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: go
deploy:
- provider: script
skip_cleanup: true
script: curl -sL https://git.io/goreleaser | bash
on:
tags: true
condition: $TRAVIS_OS_NAME = linux
62 changes: 43 additions & 19 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"context"
"encoding/json"
"fmt"
"golang.org/x/oauth2"
"io/ioutil"
"net/http"
"net/url"

"golang.org/x/oauth2"
)

const apiURL = "https://api.tech26.de"
Expand Down Expand Up @@ -105,13 +106,13 @@ type Cards []struct {
PublicToken interface{} `json:"publicToken"`
Pan interface{} `json:"pan"`
MaskedPan string `json:"maskedPan"`
ExpirationDate int64 `json:"expirationDate"`
ExpirationDate TimeStamp `json:"expirationDate"`
CardType string `json:"cardType"`
Status string `json:"status"`
CardProduct interface{} `json:"cardProduct"`
CardProductType string `json:"cardProductType"`
PinDefined interface{} `json:"pinDefined"`
CardActivated interface{} `json:"cardActivated"`
PinDefined TimeStamp `json:"pinDefined"`
CardActivated TimeStamp `json:"cardActivated"`
UsernameOnCard string `json:"usernameOnCard"`
ExceetExpressCardDelivery interface{} `json:"exceetExpressCardDelivery"`
Membership interface{} `json:"membership"`
Expand Down Expand Up @@ -202,18 +203,31 @@ func NewClient(a Auth) (*Client, error) {
return (*Client)(c.Client(ctx, tok)), nil
}

func (c *Client) n26Request(endpoint string, params map[string]string) []byte {
func (c *Client) n26Request(requestMethod, endpoint string, params map[string]string) []byte {
var req *http.Request
var err error

u, _ := url.ParseRequestURI(apiURL)
u.Path = endpoint

u.RawQuery = mapToQuery(params).Encode()

res, _ := (*http.Client)(c).Get(u.String())
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
switch requestMethod {
case http.MethodGet:
req, err = http.NewRequest(http.MethodGet, u.String(), nil)
check(err)
case http.MethodPost:
req, err = http.NewRequest(http.MethodPost, u.String(), nil)
check(err)
}

res, err := (*http.Client)(c).Do(req)
check(err)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
check(err)
return body
}

func mapToQuery(params map[string]string) url.Values {
values := url.Values{}
for k, v := range params {
Expand All @@ -223,7 +237,7 @@ func mapToQuery(params map[string]string) url.Values {
}

func (auth *Client) GetBalance(retType string) (string, *Balance) {
body := auth.n26Request("/api/accounts", nil)
body := auth.n26Request(http.MethodGet, "/api/accounts", nil)
balance := &Balance{}
check(json.Unmarshal(body, &balance))
identedJSON, _ := json.MarshalIndent(&balance, "", " ")
Expand All @@ -234,7 +248,7 @@ func (auth *Client) GetBalance(retType string) (string, *Balance) {
}

func (auth *Client) GetInfo(retType string) (string, *PersonalInfo) {
body := auth.n26Request("/api/me", nil)
body := auth.n26Request(http.MethodGet, "/api/me", nil)
info := &PersonalInfo{}
check(json.Unmarshal(body, &info))
identedJSON, _ := json.MarshalIndent(&info, "", " ")
Expand All @@ -245,7 +259,7 @@ func (auth *Client) GetInfo(retType string) (string, *PersonalInfo) {
}

func (auth *Client) GetStatus(retType string) (string, *Statuses) {
body := auth.n26Request("/api/me/statuses", nil)
body := auth.n26Request(http.MethodGet, "/api/me/statuses", nil)
status := &Statuses{}
check(json.Unmarshal(body, &status))
identedJSON, _ := json.MarshalIndent(&status, "", " ")
Expand All @@ -256,7 +270,7 @@ func (auth *Client) GetStatus(retType string) (string, *Statuses) {
}

func (auth *Client) GetAddresses(retType string) (string, *Addresses) {
body := auth.n26Request("/api/addresses", nil)
body := auth.n26Request(http.MethodGet, "/api/addresses", nil)
addresses := &Addresses{}
check(json.Unmarshal(body, &addresses))
identedJSON, _ := json.MarshalIndent(&addresses, "", " ")
Expand All @@ -267,7 +281,7 @@ func (auth *Client) GetAddresses(retType string) (string, *Addresses) {
}

func (auth *Client) GetCards(retType string) (string, *Cards) {
body := auth.n26Request("/api/v2/cards", nil)
body := auth.n26Request(http.MethodGet, "/api/v2/cards", nil)
cards := &Cards{}
check(json.Unmarshal(body, &cards))
identedJSON, _ := json.MarshalIndent(&cards, "", " ")
Expand All @@ -278,7 +292,7 @@ func (auth *Client) GetCards(retType string) (string, *Cards) {
}

func (auth *Client) GetLimits(retType string) (string, *Limits) {
body := auth.n26Request("/api/settings/account/limits", nil)
body := auth.n26Request(http.MethodGet, "/api/settings/account/limits", nil)
limits := &Limits{}
check(json.Unmarshal(body, &limits))
identedJSON, _ := json.MarshalIndent(&limits, "", " ")
Expand All @@ -289,7 +303,7 @@ func (auth *Client) GetLimits(retType string) (string, *Limits) {
}

func (auth *Client) GetContacts(retType string) (string, *Contacts) {
body := auth.n26Request("/api/smrt/contacts", nil)
body := auth.n26Request(http.MethodGet, "/api/smrt/contacts", nil)
contacts := &Contacts{}
check(json.Unmarshal(body, &contacts))
identedJSON, _ := json.MarshalIndent(&contacts, "", " ")
Expand All @@ -313,7 +327,7 @@ func (auth *Client) GetTransactions(from, to TimeStamp) (*Transactions, error) {
params["from"] = fmt.Sprint(from.AsMillis())
params["to"] = fmt.Sprint(to.AsMillis())
}
body := auth.n26Request("/api/smrt/transactions", params)
body := auth.n26Request(http.MethodGet, "/api/smrt/transactions", params)
transactions := &Transactions{}
if err := json.Unmarshal(body, &transactions); err != nil {
return nil, err
Expand All @@ -322,7 +336,7 @@ func (auth *Client) GetTransactions(from, to TimeStamp) (*Transactions, error) {
}

func (auth *Client) GetStatements(retType string) (string, *Statements) {
body := auth.n26Request("/api/statements", nil)
body := auth.n26Request(http.MethodGet, "/api/statements", nil)
statements := &Statements{}
check(json.Unmarshal(body, &statements))
identedJSON, _ := json.MarshalIndent(&statements, "", " ")
Expand All @@ -333,14 +347,24 @@ func (auth *Client) GetStatements(retType string) (string, *Statements) {
}

func (auth *Client) GetStatementPDF(ID string) {
body := auth.n26Request(fmt.Sprintf("%s%s", "/api/statements/", ID), nil)
body := auth.n26Request(http.MethodGet, fmt.Sprintf("/api/statements/%s", ID), nil)
ioutil.WriteFile(
fmt.Sprintf("%s.pdf", ID),
body,
0750,
)
}

func (auth *Client) BlockCard(ID string) {
_ = auth.n26Request(http.MethodPost, fmt.Sprintf("/api/cards/%s/block", ID), nil)
fmt.Printf("\nYour card with ID: %s is DISABLED\n\n", ID)
}

func (auth *Client) UnblockCard(ID string) {
_ = auth.n26Request(http.MethodPost, fmt.Sprintf("/api/cards/%s/unblock", ID), nil)
fmt.Printf("\nYour card with ID: %s is ACTIVE\n\n", ID)
}

func check(e error) {
if e != nil {
panic(e)
Expand Down
35 changes: 32 additions & 3 deletions cmd/n26/n26.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import (
"github.com/urfave/cli"
)

const (
appVersion = "1.4.2"
)

func check(e error) {
if e != nil {
panic(e)
Expand All @@ -33,7 +37,7 @@ func authentication() (*n26.Client, error) {
check(err)
password = string(maskedPass)
}
return n26.NewClient(n26.Auth{username, password})
return n26.NewClient(n26.Auth{UserName: username, Password: password})
}

// Interface for generic data writer that has a header and data table e.g. table writer and csv writer
Expand All @@ -46,7 +50,7 @@ type transactionWriter interface {

func main() {
app := cli.NewApp()
app.Version = "1.4.1"
app.Version = appVersion
app.UsageText = "n26 command [json|csv|statement ID]"
app.Name = "N26"
app.Usage = "your N26 Bank financial information on the command line"
Expand Down Expand Up @@ -156,14 +160,17 @@ func main() {
for _, card := range *cards {
data = append(data,
[]string{
card.ID,
card.UsernameOnCard,
card.CardType,
card.CardProductType,
card.MaskedPan,
card.ExpirationDate.String(),
card.Status,
},
)
}
NewTableWriter().WriteData([]string{"Name on Card", "Type", "Product type", "Number"}, data)
NewTableWriter().WriteData([]string{"ID", "Name on Card", "Type", "Product type", "Number", "Expiration Date", "Status"}, data)
}
return nil
},
Expand Down Expand Up @@ -285,6 +292,28 @@ func main() {
return nil
},
},
{
Name: "block",
Usage: "blocks a card",
ArgsUsage: "[card ID]",
Action: func(c *cli.Context) error {
API, err := authentication()
check(err)
API.BlockCard(c.Args().First())
return nil
},
},
{
Name: "unblock",
Usage: "unblocks a card",
ArgsUsage: "[card ID]",
Action: func(c *cli.Context) error {
API, err := authentication()
check(err)
API.UnblockCard(c.Args().First())
return nil
},
},
}

sort.Sort(cli.CommandsByName(app.Commands))
Expand Down

0 comments on commit 2a6dc4b

Please sign in to comment.