Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add accounts config #3

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ec76558
First stab at adding accounts config
david-caro Dec 3, 2022
88f6bdc
expenses-64 // retrieve balance ids for all accounts
Dinika Dec 3, 2022
9ef0a0e
Expenses-64 // Retrieve transactions for both accounts
Dinika Dec 4, 2022
4899b64
Add transactions from wise to expenses to review
Dinika Dec 11, 2022
77bbf6c
Add schema for expenses_in_review
Dinika Dec 11, 2022
0868cc5
Send discovered expenses to frontend
Dinika Mar 12, 2023
5aef398
Expenses in review should be linked to accounts
Dinika Mar 12, 2023
9769ebc
dev: Fix db setup
david-caro May 27, 2023
7de015f
Update readme with server & db installation instructions
Dinika May 27, 2023
b237f50
Add dev dockerfile and start script
david-caro Jun 4, 2023
793b524
Pass args to start_dev
david-caro Jun 4, 2023
33d9d58
Use container database when starting dev
david-caro Jun 4, 2023
d45d9ba
Update db schema and fake data
david-caro Jun 4, 2023
5f54c7a
start_dev.sh: use the local network ip
david-caro Jun 4, 2023
57d870e
start_dev.sh: remove trailing space
david-caro Jun 4, 2023
4a90c2b
Pin mariadb to lts
david-caro Jun 11, 2023
4264255
Add github workflow
david-caro Jun 11, 2023
91194c0
Fix account id available when fetching tw balance
Dinika Jun 12, 2023
fb7f2ae
Implement API to show count of expenses to review
Dinika Jun 18, 2023
be5b9bc
Keep the gradle cache between builds for faster startup
Dinika Jun 18, 2023
9a3891b
Implement api to start review
Dinika Jun 18, 2023
5e18094
Add script to connect to dev db
Dinika Jun 18, 2023
177ce34
scripts: add upgrade_db script
david-caro Jun 25, 2023
337e03e
ci: add verbose running
david-caro Jun 30, 2023
7299e2a
ci: first api tests
david-caro Jun 30, 2023
8d2031d
Merge pull request #4 from farting-lizards/david_upgrade_db
Dinika Jul 2, 2023
648b28c
functional-tests: don't expect floats
david-caro Jul 14, 2023
df0dbf4
Inline hour from now
Dinika Jul 2, 2023
b9f2c3f
Release expenses from the queue of review
Dinika Jul 2, 2023
1407364
Accept/Reject expense
Dinika Jul 14, 2023
8893510
build: fix logging to stdout and dockerfile to match
david-caro Feb 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: CI
on:
push:
branches:
- main
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Install packages
run: |
sudo apt update
sudo apt-get -y install podman python3-virtualenv jq
python -m virtualenv tests-venv
source tests-venv/bin/activate
pip install bats-core-pkg
- name: Get source
uses: actions/checkout@v3
with:
path: "expenses-server"
- name: start app
run: |
set -x
cd expenses-server
./scripts/start_devdb.sh

# fake accoutns config
mkdir -p ../home-lab-secrets/home_automation/expenses/
echo "accounts-config: {'accounts': []}" > ../home-lab-secrets/home_automation/expenses/application-accounts.yml

./scripts/start_dev.sh notail
- name: run tests
run: |
source tests-venv/bin/activate
cd expenses-server
bats_core_pkg --verbose-run --trace api-tests/
8 changes: 8 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# FROM --platform=arm64 docker.io/library/gradle:jdk11
# In dev we use x86, in prod we use arm64 (raspberry)
FROM --platform=amd64 docker.io/library/gradle:jdk11
ENV GRADLE_USER_HOME=/src/.gradle
EXPOSE 8080/tcp
USER 1000
WORKDIR /src
CMD ["/src/gradlew", "bootRun"]
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Dev install

You'll need java 11 jdk installed, on fedora:

> sudo dnf install java-11-openjdk-devel

### Installing java 11

In case you have multiple versions of java installed, you will have to configure your
system to use java 11. The following java tools will have to be updated:

```bash
# find java tools that need to be configured to use version 11
$ sudo alternatives --list | grep java | grep manual
java_sdk_openjdk manual /usr/lib/jvm/java-11-openjdk-11.0.19.0.7-1.fc38.x86_64
jre_openjdk manual /usr/lib/jvm/java-11-openjdk-11.0.19.0.7-1.fc38.x86_64
java manual /usr/lib/jvm/java-11-openjdk-11.0.19.0.7-1.fc38.x86_64/bin/java
javac manual /usr/lib/jvm/java-11-openjdk-11.0.19.0.7-1.fc38.x86_64/bin/javac
```
This is how you can configure the above java tools to use version 11
```bash
$ for alternative in $(sudo alternatives --list | grep java | awk '{print $1}' | grep -v '\(17\|11\)'); do sudo alternatives --config "$alternative"; done
```

### Running the server locally

1. Start the database locally - Simply run the following script to start the server. The script also populates the database with some dummy data:
> Make sure you are in the root directory of this project to run the following command.
```bash
$ sudo ./scripts/start_devdb.sh populate
```

2. Start the server locally - You can either use the "Run" button of your IDE (such as intellij) to run the server application or run the following command:
```bash
./gradlew bootRun
```
85 changes: 85 additions & 0 deletions api-tests/helpers.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env bats
BASE_URL=http://127.0.0.1:8080

do_post() {
local path="${1?}"
local data="${2?}"
curl \
-X POST \
--silent \
"${BASE_URL}/${path}" \
-H 'Content-Type: application/json' \
-d "$data"
}

do_put() {
local path="${1?}"
local data="${2?}"
curl \
-X PUT \
--silent \
"${BASE_URL}/${path}" \
-H 'Content-Type: application/json' \
-d "$data"
}

do_get() {
local path="${1?}"
curl \
-X GET \
--silent \
"${BASE_URL}/${path}" \
-H 'Content-Type: application/json'
}

do_delete() {
local path="${1?}"
curl \
-X DELETE \
--silent \
"${BASE_URL}/${path}" \
-H 'Content-Type: application/json'
}

is_equal() {
local left="${1?}"
local right="${2?}"
diff <( printf '%s' "$left" ) <( printf "%s" "$right" ) \
&& return 0
echo -e "is_equal failed\nleft: $left\nright: $right" >&2
return 1
}

match_regex() {
local regex="${1?}"
local what="${2?}"
[[ "$what" =~ $regex ]] && return 0
echo -e "match_regex failed\nregex: '$regex'\nwhat: $what" >&2
return 1
}

json_has_equal() {
local key="${1?}"
local value="${2?}"
local data="${3?}"
local cur_value=$(echo "$data" | jq -r ".$key") \
&& is_equal "$cur_value" "$value" \
&& return 0
echo -e "json_has_equal: key '$key' with value '$value' not found in \n$data" >&2
return 1
}

json_has_match() {
local key="${1?}"
local match="${2?}"
local data="${3?}"
local cur_value=$(echo "$data" | jq -r ".$key")
match_regex "$match" "$cur_value" && return 0
echo -e "json_has_match: key '$key' value '$cur_value' does not match '$match'" >&2
return 1
}

json_get() {
local key="${1?}"
jq -r ".$key"
}
114 changes: 114 additions & 0 deletions api-tests/test_expenses.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env bats

# per whole file
setup_file() {
curdir="${BATS_TEST_FILENAME%/*}"
db_host="127.0.0.1"
test_db="expenses"
test_db_pass="dummypass"
test_db_user="expenses"
mysql="mysql \
--host=$db_host \
--port=3306 \
--protocol=tcp \
--user=$test_db_user \
--password=$test_db_pass"

$mysql -e "drop database if exists $test_db"
$mysql -e "create database $test_db"
$mysql "$test_db" < $curdir/../db/schema.sql
$mysql -e "insert into accounts values (0, 'Test account 0'),(1, 'Test account 1')" "$test_db"
$mysql -e "select * from expenses;" "$test_db"
}


# per test
setup() {
load helpers
}

@test "I can get the expenses (empty database)" {
run do_get "api/expenses"

[[ "$status" == "0" ]]
is_equal \
'[]' \
"$output"
}

@test "I can create a new expense" {
new_expense='{
"currency": "EUR",
"amount": "42.0",
"category": "eating-out",
"description": "Some fake expense number 1",
"accountId": 1,
"timestamp": "'"$(date +%Y-%m-%dT%H:%M:%SZ)"'"
}'
run do_post "api/expenses" "$new_expense"

[[ "$status" == "0" ]]
json_has_match 'amount' '42' "$output"
json_has_match 'category' 'eating-out' "$output"
json_has_match 'description' 'Some fake expense number 1' "$output"
json_has_match 'account.id' '1' "$output"
}

@test "I can update an expense" {
new_expense='{
"currency": "EUR",
"amount": "42.0",
"category": "eating-out",
"description": "Some fake expense number 1",
"accountId": 1,
"timestamp": "'"$(date +%Y-%m-%dT%H:%M:%SZ)"'"
}'
run do_post "api/expenses" "$new_expense"

[[ "$status" == "0" ]]
json_has_match 'amount' '42' "$output"

new_expense_id="$(echo "$output" | json_get "id")"
modified_expense='{
"currency": "EUR",
"amount": "84.0",
"category": "eating-out",
"description": "Some fake expense number 1",
"accountId": 1,
"timestamp": "'"$(date +%Y-%m-%dT%H:%M:%SZ)"'"
}'
run do_put "api/expenses/$new_expense_id" "$modified_expense"

[[ "$status" == "0" ]]
json_has_match "amount" '84' "$output"

run do_get "api/expenses"

json_has_match "[] | select( .id == $new_expense_id) | .amount" '84' "$output"
}

@test "I can delete an expense" {
new_expense='{
"currency": "EUR",
"amount": "42.0",
"category": "eating-out",
"description": "Some fake expense number 1",
"accountId": 1,
"timestamp": "'"$(date +%Y-%m-%dT%H:%M:%SZ)"'"
}'
run do_post "api/expenses" "$new_expense"

[[ "$status" == "0" ]]
json_has_match 'amount' '42' "$output"

new_expense_id="$(echo "$output" | json_get "id")"

run do_delete "api/expenses/$new_expense_id"

[[ "$status" == "0" ]]
[[ "$output" == "$new_expense_id" ]]

run do_get "api/expenses"

json_has_match "[] | select( .id == $new_expense_id)" '' "$output"
}
13 changes: 12 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,29 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

// Needed to sign digital signatures for wise accounts
implementation 'org.bouncycastle:bcprov-jdk15on:1.64'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.64'

compileOnly 'org.projectlombok:lombok:1.18.16'
annotationProcessor 'org.projectlombok:lombok:1.18.16'

testCompileOnly 'org.projectlombok:lombok:1.18.16'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.16'

// compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java'
}

test {
useJUnitPlatform()
}


bootRun {
jvmArgs = [
"-Dspring.config.additional-location=file:../home-lab-secrets/home_automation/expenses/"
]
}
14 changes: 2 additions & 12 deletions db/fake_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

LOCK TABLES `accounts` WRITE;
/*!40000 ALTER TABLE `accounts` DISABLE KEYS */;
INSERT INTO `accounts` VALUES (0,'fake account 1'),(1,'fake account 2');
INSERT INTO `accounts` VALUES (0,'Joint Revolut'),(1,'Wise David'),(2,'Wise Dini'),(3,'Revolut David'),(4,'Revolut Dini');
/*!40000 ALTER TABLE `accounts` ENABLE KEYS */;
UNLOCK TABLES;

Expand All @@ -41,20 +41,10 @@ UNLOCK TABLES;

LOCK TABLES `expenses` WRITE;
/*!40000 ALTER TABLE `expenses` DISABLE KEYS */;
INSERT INTO `expenses` VALUES (2,29.90,'EUR','2021-08-14 00:00:00','eating-out','Pizza',1),(3,4.10,'EUR','2021-08-14 00:00:00','eating-out','Pain au Chocolat',1),(4,38.99,'EUR','2021-08-13 00:00:00','groceries','Grand frais',1)
INSERT INTO `expenses` VALUES (2,29.90,'EUR','2021-08-14 00:00:00','eating-out','Pizza',1, NULL),(3,4.10,'EUR','2021-08-14 00:00:00','eating-out','Pain au Chocolat',1, "somedummyexternalid"),(4,38.99,'EUR','2021-08-13 00:00:00','groceries','Grand frais',1, NULL);
/*!40000 ALTER TABLE `expenses` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `hibernate_sequence`
--

LOCK TABLES `hibernate_sequence` WRITE;
/*!40000 ALTER TABLE `hibernate_sequence` DISABLE KEYS */;
INSERT INTO `hibernate_sequence` VALUES (1);
/*!40000 ALTER TABLE `hibernate_sequence` ENABLE KEYS */;
UNLOCK TABLES;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
Expand Down
1 change: 1 addition & 0 deletions db/migrations/2023-06-11-add-accounts-config.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table expenses_in_review modify column review_until timestamp not null default '1970-01-01 00:00:01.0'
Loading
Loading