2020-05-10 00:13:20 +00:00
# capsulflask
Python Flask web application for capsul.org
2020-05-10 00:22:25 +00:00
2020-05-10 00:13:20 +00:00
## how to run locally
Ensure you have the pre-requisites for the psycopg2 Postgres database adapter package
```
2020-05-12 02:25:49 +00:00
sudo apt install python3-dev libpq-dev
2020-05-10 00:13:20 +00:00
pg_config --version
```
2020-05-12 02:25:49 +00:00
Ensure you have the wonderful `pipenv` python package management and virtual environment cli
```
sudo apt install pipenv
```
2020-05-10 00:13:20 +00:00
Create python virtual environment and install packages
```
2020-05-12 02:25:49 +00:00
# install deps
pipenv install
2020-05-10 00:13:20 +00:00
```
2020-05-10 01:36:14 +00:00
Run an instance of Postgres (I used docker for this, you can use whatever you want, point is its listening on localhost:5432)
2020-05-10 00:13:20 +00:00
```
2020-05-10 18:51:54 +00:00
docker run --rm -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres
2020-05-10 00:13:20 +00:00
```
2020-05-12 01:15:11 +00:00
Modify the default email settings
```
nano capsulflask/__init__.py
```
2020-05-10 00:13:20 +00:00
Run the app
```
2020-05-15 04:54:08 +00:00
pipenv run flask run
2020-05-10 18:51:54 +00:00
```
2020-05-14 17:40:25 +00:00
Run the app in gunicorn
2020-05-11 20:13:20 +00:00
```
2020-05-15 04:54:08 +00:00
pipenv run gunicorn --bind 127.0.0.1:5000 app:app
2020-05-11 20:13:20 +00:00
```
2020-05-15 01:05:02 +00:00
-----
2020-05-14 23:03:00 +00:00
2020-05-15 01:05:02 +00:00
## cli
You can manually mess around with the database like this:
```
2020-05-15 04:54:08 +00:00
pipenv run flask cli sql -f test.sql
2020-05-15 01:05:02 +00:00
```
```
2020-05-15 04:54:08 +00:00
pipenv run flask cli sql -c 'SELECT * FROM vms'
2020-05-15 01:05:02 +00:00
```
This one selects the vms table with the column name header:
```
2020-05-15 04:54:08 +00:00
pipenv run flask cli sql -c "SELECT string_agg(column_name::text, ', ') from information_schema.columns WHERE table_name='vms'; SELECT * from vms"
2020-05-15 01:05:02 +00:00
```
How to modify a payment manually, like if you get a chargeback or to fix customer payment issues:
```
2020-05-15 04:54:08 +00:00
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
2020-05-15 01:05:02 +00:00
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, FALSE
2020-05-15 04:54:08 +00:00
$ pipenv run flask cli sql -c "UPDATE payments SET invalidated = True WHERE id = 1"
2020-05-15 01:05:02 +00:00
1 rows affected.
2020-05-15 04:54:08 +00:00
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
2020-05-15 01:05:02 +00:00
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, TRUE
```
How you would kick off the scheduled task:
```
2020-05-15 04:54:08 +00:00
pipenv run flask cli cron-task
2020-05-15 01:05:02 +00:00
```
-----
## postgres database schema management
2020-05-10 18:51:54 +00:00
capsulflask has a concept of a schema version. When the application starts, it will query the database for a table named
`schemaversion` that has one row and one column (`version`). If the `version` it finds is not equal to the `desiredSchemaVersion` variable set in `db.py` , it will run migration scripts from the `schema_migrations` folder one by one until the `schemaversion` table shows the correct version.
For example, the script named `02_up_xyz.sql` should contain code that migrates the database from schema version 1 to schema version 2. Likewise, the script `02_down_xyz.sql` should contain code that migrates from schema version 2 back to schema version 1.
**IMPORTANT: if you need to make changes to the schema, make a NEW schema version. DO NOT EDIT the existing schema versions.**
2020-05-12 01:15:11 +00:00
In general, for safety, schema version upgrades should not delete data. Schema version downgrades will simply throw an error and exit for now.
2020-05-14 17:40:25 +00:00
2020-05-15 01:05:02 +00:00
-----
2020-05-14 17:40:25 +00:00
2020-05-15 01:05:02 +00:00
## how to setup btcpay server
2020-05-14 17:40:25 +00:00
2020-05-15 23:18:19 +00:00
Generate a private key and the accompanying bitpay SIN for the btcpay API client.
2020-05-14 17:40:25 +00:00
I used this code as an example: https://github.com/bitpay/bitpay-python/blob/master/bitpay/key_utils.py#L6
```
$ python ./readme/generate_btcpay_keys.py
```
It should output something looking like this:
```
-----BEGIN EC PRIVATE KEY-----
EXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK
oUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq
NQ+cpBvPDbyrDk9+Uf/sEaRCma094g==
-----END EC PRIVATE KEY-----
EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE
```
In order to register the key with the btcpay server, you have to first generate a pairing token using the btcpay server interface.
This requires your btcpay server account to have access to the capsul store. Ask Cass about this.
Navigate to `Manage store: Access Tokens` at: `https://btcpay.cyberia.club/stores/<store-id>/Tokens`
![](readme/btcpay_sin_pairing.jpg)
Finally, send an http request to the btcpay server to complete the pairing:
```
curl -H "Content-Type: application/json" https://btcpay.cyberia.club/tokens -d "{'id': 'EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE', 'pairingCode': 'XXXXXXX'}"
```
It should respond with a token:
```
{"data":[{"policies":[],"pairingCode":"XXXXXXX","pairingExpiration":1589473817597,"dateCreated":1589472917597,"facade":"merchant","token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","label":"capsulflask"}]}
```
And you should see the token in the btcpay server UI:
![](readme/paired.jpg)
2020-05-15 04:54:08 +00:00
Now simply set your `BTCPAY_PRIVATE_KEY` variable in `.env`
2020-05-14 17:40:25 +00:00
```
BTCPAY_PRIVATE_KEY='-----BEGIN EC PRIVATE KEY-----
EXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK
oUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq
NQ+cpBvPDbyrDk9+Uf/sEaRCma094g==
-----END EC PRIVATE KEY-----'
```