Merge pull request #55 from SamR1/project-refactoring-and-packaging

Project refactoring and packaging
This commit is contained in:
Sam 2020-09-19 14:34:48 +02:00 committed by GitHub
commit 984345da8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
223 changed files with 5147 additions and 5368 deletions

View File

@ -1,4 +1,4 @@
[run] [run]
omit = omit =
fittrackee_api/.venv/* fittrackee/.venv/*
fittrackee_api/fittrackee_api/tests/* fittrackee/tests/*

28
.env.example Normal file
View File

@ -0,0 +1,28 @@
# Custom variables initialisation
# (can overwrite variables present in Makefile.config)
# Application
# export FLASK_APP=fittrackee
# export HOST=
# export PORT=
# export APP_SETTINGS=fittrackee.config.ProductionConfig
export APP_SECRET_KEY=
# export APP_WORKERS=
export APP_LOG=fittrackee.log
export UPLOAD_FOLDER=
# Database
# export DATABASE_URL=postgres://fittrackee:fittrackee@${HOST}:5432/fittrackee
export DATABASE_DISABLE_POOLING=
# Emails
export UI_URL=
export EMAIL_URL=
export SENDER_EMAIL=
export REDIS_URL=
# export WORKERS_PROCESSES=
# Activities
export TILE_SERVER_URL=
export MAP_ATTRIBUTION=
export WEATHER_API_KEY=

View File

@ -1,5 +1,6 @@
[flake8] [flake8]
per-file-ignores = per-file-ignores =
fittrackee_api/fittrackee_api/activities/stats.py:E501 fittrackee/activities/stats.py:E501
fittrackee_api/fittrackee_api/tests/test_email.py:E501 fittrackee/application/app_config.py:E501
fittrackee_api/fittrackee_api/tests/test_email_template_password_request.py:E501 fittrackee/tests/test_email.py:E501
fittrackee/tests/test_email_template_password_request.py:E501

8
.gitignore vendored
View File

@ -3,18 +3,20 @@
Makefile.custom.config Makefile.custom.config
# MPWO_API # API
############### ###############
__pycache__ __pycache__
uploads uploads
.cache .cache
.coverage .coverage
coverage.xml coverage.xml
.env
.pytest_cache .pytest_cache
.venv .venv
/fittrackee_api.egg-info/ /fittrackee.egg-info/
/dist
# MPWO_CLIENT # CLIENT
############### ###############
# dependencies # dependencies

65
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,65 @@
image: python:3.8
variables:
POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee
POSTGRES_PASSWORD: fittrackee
POSTGRES_HOST: postgres
APP_SETTINGS: fittrackee.config.TestingConfig
DATABASE_TEST_URL: postgres://fittrackee:fittrackee@postgres:5432/fittrackee_test
EMAIL_URL: smtp://none:none@0.0.0.0:1025
FLASK_APP: fittrackee/__main__.py
SENDER_EMAIL: fittrackee@example.com
services:
- name: postgres:latest
alias: postgres
stages:
- tests
- selenium
.python:
stage: tests
before_script:
- pip install --quiet poetry
- poetry config virtualenvs.create false
- poetry install --no-interaction --quiet
script:
- pytest fittrackee -p no:warnings --cov fittrackee --cov-report term-missing
lint:
extends: .python
script:
- pytest --flake8 --isort --black -m "flake8 or isort or black" fittrackee e2e --ignore=fittrackee/migrations
python-3.7:
extends: .python
image: python:3.7
python-3.8:
extends: .python
python-3.9-rc:
extends: .python
image: python:3.9-rc
allow_failure: true
firefox:
stage: selenium
services:
- name: postgres:latest
alias: postgres
- name: selenium/standalone-firefox
alias: selenium
before_script:
- pip install --quiet poetry
- poetry config virtualenvs.create false
- poetry install --no-interaction --quiet
- flask db upgrade --directory fittrackee/migrations
- flask init-data
- setsid nohup flask run --with-threads -h 0.0.0.0 -p 5000 >> nohup.out 2>&1 &
- export TEST_APP_URL=http://$(hostname --ip-address):5000
- sleep 5
script:
- pytest e2e --driver Remote --capability browserName firefox --host selenium --port 4444

View File

@ -1,49 +0,0 @@
language: node_js
node_js: '13'
dist: trusty
sudo: required
addons:
chrome: stable
apt:
update: true
packages:
- dpkg
- fluxbox
services:
- docker
env:
global:
- DOCKER_COMPOSE_VERSION=1.22.0
before_install:
- stty cols 80
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
before_script:
- export DATABASE_TEST_URL=postgres://postgres:@localhost:5432/fittrackee_test
- export APP_SETTINGS=fittrackee_api.config.TestingConfig
- export REACT_APP_API_URL=http://127.0.0.1
- export NODE_ENV=development
- export TEST_URL=http://127.0.0.1
- export UI_URL=http://127.0.0.1:3000
- export EMAIL_URL=smtp://none:none@0.0.0.0:1025
- export SENDER_EMAIL=fittrackee@example.com
- export DISPLAY=:99.0
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
- sh -e /etc/init.d/xvfb start
- sleep 3
- fluxbox >/dev/null 2>&1 &
- docker-compose -f docker-compose-ci.yml up --build -d
script:
- sh test.sh
after_script:
- docker-compose down

View File

@ -1,14 +1,21 @@
# Change log # Change log
## Version 0.x.x (unreleased) ## Version 0.4.0 (unreleased)
This version introduces some major changes:
- Installation becomes more easy.
⚠️ Warning: please read [installation documentation](https://samr1.github.io/FitTrackee/installation.html), some environment variables and files have been renamed.
- It's now possible to change the tile provider for maps. The default tile server is now **OpenStreetMap**'s standard tile layer (replacing **ThunderForest Outdoors**),
see [Map tile server in documentation](https://samr1.github.io/FitTrackee/installation.html#map-tile-server).
### Issues Closed ### Issues Closed
#### New Features #### New Features
* [#54](https://github.com/SamR1/Fittrackee/issues/54) - Tile server can be changed * [#54](https://github.com/SamR1/Fittrackee/issues/54) - Tile server can be changed
* [#53](https://github.com/SamR1/Fittrackee/issues/53) - Simplify FitTrackee installation
In this release 1 issue weas closed. In this release 2 issue were closed.
## Version 0.3.0 - Administration (2020/07/15) ## Version 0.3.0 - Administration (2020/07/15)

View File

@ -1,17 +1,20 @@
include Makefile.config include Makefile.config
-include Makefile.custom.config -include .env
.SILENT: .SILENT:
make-p: make-p:
# Launch all P targets in parallel and exit as soon as one exits. # Launch all P targets in parallel and exit as soon as one exits.
set -m; (for p in $(P); do ($(MAKE) $$p || kill 0)& done; wait) set -m; (for p in $(P); do ($(MAKE) $$p || kill 0)& done; wait)
build-client: build-client: lint-client
$(NPM) build cd fittrackee_client && $(NPM) build
clean-install: clean-install:
rm -fr $(NODE_MODULES) rm -fr $(NODE_MODULES)
rm -fr $(VENV) rm -fr $(VENV)
rm -rf *.egg-info
rm -rf .pytest_cache
rm -rf dist/
html: html:
rm -rf docsrc/build rm -rf docsrc/build
@ -25,9 +28,9 @@ html:
cp -a docsrc/build/html/. docs cp -a docsrc/build/html/. docs
install-db: install-db:
psql -U postgres -f fittrackee_api/db/create.sql psql -U postgres -f db/create.sql
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FLASK) db upgrade --directory $(MIGRATIONS)
$(FLASK) initdata $(FLASK) init-data
init-app-config: init-app-config:
$(FLASK) init-app-config $(FLASK) init-app-config
@ -35,15 +38,16 @@ init-app-config:
init-db: init-db:
$(FLASK) drop-db $(FLASK) drop-db
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FLASK) db upgrade --directory $(MIGRATIONS)
$(FLASK) initdata $(FLASK) init-data
install: install-client install-python install: install-client install-python
install-client: install-client:
$(NPM) install --prod cd fittrackee_client && $(NPM) install --prod
install-client-dev: install-client-dev:
$(NPM) install # https://github.com/facebook/create-react-app/issues/8688
cd fittrackee_client && $(NPM) install && sed -i '/process.env.CI/ s/isInteractive [|]*//' node_modules/react-scripts/scripts/start.js
install-dev: install-client-dev install-python-dev install-dev: install-client-dev install-python-dev
@ -53,21 +57,21 @@ install-python:
install-python-dev: install-python-dev:
$(POETRY) install $(POETRY) install
lint-all: lint-python lint-react lint-all: lint-python lint-client
lint-all-fix: lint-python-fix lint-react-fix lint-all-fix: lint-python-fix lint-client-fix
lint-python: lint-python:
$(PYTEST) --flake8 --isort --black -m "flake8 or isort or black" fittrackee_api --ignore=fittrackee_api/migrations $(PYTEST) --flake8 --isort --black -m "flake8 or isort or black" fittrackee e2e --ignore=fittrackee/migrations
lint-python-fix: lint-python-fix:
$(BLACK) fittrackee_api $(BLACK) fittrackee e2e
lint-react: lint-client:
$(NPM) lint cd fittrackee_client && $(NPM) lint
lint-react-fix: lint-client-fix:
$(NPM) lint-fix cd fittrackee_client && $(NPM) lint-fix
mail: mail:
docker run -d -e "MH_STORAGE=maildir" -v /tmp/maildir:/maildir -p 1025:1025 -p 8025:8025 mailhog/mailhog docker run -d -e "MH_STORAGE=maildir" -v /tmp/maildir:/maildir -p 1025:1025 -p 8025:8025 mailhog/mailhog
@ -79,43 +83,37 @@ recalculate:
$(FLASK) recalculate $(FLASK) recalculate
run: run:
$(MAKE) P="run-server run-workers run-client" make-p $(MAKE) P="run-server run-workers" make-p
run-client:
serve -s fittrackee_client/build -l 3000 >> serve.log 2>&1
run-server: run-server:
cd fittrackee_api && $(GUNICORN) -b 127.0.0.1:5000 "fittrackee_api:create_app()" --error-logfile ../gunicorn.log cd fittrackee && $(GUNICORN) -b 127.0.0.1:5000 "fittrackee:create_app()" --error-logfile ../gunicorn.log
run-workers: run-workers:
$(FLASK) worker --processes=$(WORKERS_PROCESSES) >> dramatiq.log 2>&1 $(FLASK) worker --processes=$(WORKERS_PROCESSES) >> dramatiq.log 2>&1
serve-python: serve-python:
$(FLASK) run --with-threads -h $(HOST) -p $(API_PORT) $(FLASK) run --with-threads -h $(HOST) -p $(PORT)
serve-python-dev: serve-python-dev:
$(FLASK) run --with-threads -h $(HOST) -p $(API_PORT) --cert=adhoc $(FLASK) run --with-threads -h $(HOST) -p $(PORT) --cert=adhoc
serve-react: serve-client:
$(NPM) start cd fittrackee_client && $(NPM) start
serve: serve:
$(MAKE) P="serve-react serve-python" make-p $(MAKE) P="serve-client serve-python" make-p
serve-dev: serve-dev:
$(MAKE) P="serve-react serve-python-dev" make-p $(MAKE) P="serve-client serve-python-dev" make-p
test-e2e: init-db test-e2e: init-db
$(NPM) test $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
test-e2e-client: init-db
E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
test-python: test-python:
$(PYTEST) fittrackee_api --cov-config .coveragerc --cov=fittrackee_api --cov-report term-missing $(PYTEST_ARGS) $(PYTEST) fittrackee --cov-config .coveragerc --cov=fittrackee --cov-report term-missing $(PYTEST_ARGS)
test-python-xml:
$(PYTEST) fittrackee_api --cov-config .coveragerc --cov=fittrackee_api --cov-report xml
update-cov: test-python-xml
$(COV) -r coverage.xml
upgrade-db: upgrade-db:
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FLASK) db upgrade --directory $(MIGRATIONS)

View File

@ -1,14 +1,20 @@
HOST = 0.0.0.0 export HOST = 0.0.0.0
API_PORT = 5000 export PORT = 5000
CLIENT_PORT = 3000 export CLIENT_PORT = 3000
export FLASK_APP = $(PWD)/fittrackee_api/server.py export FLASK_APP = $(PWD)/fittrackee/__main__.py
export APP_SETTINGS=fittrackee_api.config.DevelopmentConfig export MIGRATIONS = $(PWD)/fittrackee/migrations
export FLASK_ENV=development export APP_WORKERS = 1
export TEST_URL = http://$(HOST):$(CLIENT_PORT) export WORKERS_PROCESSES = 1
# for dev env
export FLASK_ENV = development
export APP_SETTINGS = fittrackee.config.DevelopmentConfig
export DATABASE_URL = postgres://fittrackee:fittrackee@$(HOST):5432/fittrackee export DATABASE_URL = postgres://fittrackee:fittrackee@$(HOST):5432/fittrackee
export DATABASE_TEST_URL = postgres://fittrackee:fittrackee@$(HOST):5432/fittrackee_test export DATABASE_TEST_URL = postgres://fittrackee:fittrackee@$(HOST):5432/fittrackee_test
export MIGRATIONS = $(PWD)/fittrackee_api/migrations export TEST_APP_URL = http://$(HOST):$(PORT)
export TEST_CLIENT_URL = http://$(HOST):$(CLIENT_PORT)
export REACT_APP_API_URL= $(TEST_APP_URL)
# Python env # Python env
PYTHON_VERSION ?= python PYTHON_VERSION ?= python
@ -18,11 +24,10 @@ POETRY = poetry
FLASK = $(VENV)/bin/flask FLASK = $(VENV)/bin/flask
PYTEST = $(VENV)/bin/py.test -c pyproject.toml -W ignore::DeprecationWarning PYTEST = $(VENV)/bin/py.test -c pyproject.toml -W ignore::DeprecationWarning
GUNICORN = $(VENV)/bin/gunicorn GUNICORN = $(VENV)/bin/gunicorn
COV = $(VENV)/bin/python-codacy-coverage
BLACK = $(VENV)/bin/black BLACK = $(VENV)/bin/black
# Node env # Node env
NODE_MODULES = $(PWD)/node_modules NODE_MODULES = $(PWD)/fittrackee_client/node_modules
NPM ?= yarn NPM ?= yarn
#Sphinx Docs #Sphinx Docs

View File

@ -1,13 +0,0 @@
WORKERS_PROCESSES = 1
export REACT_APP_API_URL=
export TILE_SERVER_URL=
export MAP_ATTRIBUTION=
export WEATHER_API=
export UI_URL=
export EMAIL_URL=
export SENDER_EMAIL=
export REDIS_URL=
# for dev env
export CODACY_PROJECT_TOKEN=

View File

@ -7,8 +7,8 @@
[![React Version](https://img.shields.io/badge/react-16.13-brightgreen.svg)](https://reactjs.org/) [![React Version](https://img.shields.io/badge/react-16.13-brightgreen.svg)](https://reactjs.org/)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/290a285f22e94132904dc13b4dd19d1d)](https://www.codacy.com/app/SamR1/FitTrackee) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/290a285f22e94132904dc13b4dd19d1d)](https://www.codacy.com/app/SamR1/FitTrackee)
[![Codacy Coverage Badge](https://api.codacy.com/project/badge/Coverage/290a285f22e94132904dc13b4dd19d1d)](https://www.codacy.com/app/SamR1/FitTrackee)<sup><sup>1</sup></sup> [![pipeline status](https://gitlab.com/SamR1/FitTrackee/badges/master/pipeline.svg)](https://gitlab.com/SamR1/FitTrackee/-/commits/master) <sup><sup>1</sup></sup>
[![Build Status](https://travis-ci.org/SamR1/FitTrackee.svg?branch=master)](https://travis-ci.org/SamR1/FitTrackee) [![coverage report](https://gitlab.com/SamR1/FitTrackee/badges/master/coverage.svg)](https://gitlab.com/SamR1/FitTrackee/-/commits/master)
--- ---
@ -24,10 +24,10 @@ Examples (for Android):
Maps are displayed using [Open Street Map](https://www.openstreetmap.org). Maps are displayed using [Open Street Map](https://www.openstreetmap.org).
It is also possible to add a workout without a gpx file. It is also possible to add a workout without a gpx file.
**Still under development (not ready for production).** **Still under heavy development (some features may be unstable).**
(see [issues](https://github.com/SamR1/FitTrackee/issues) and [documentation](https://samr1.github.io/FitTrackee) for more information) (see [issues](https://github.com/SamR1/FitTrackee/issues) and [documentation](https://samr1.github.io/FitTrackee) for more information)
![FitTrackee Dashboard](docsrc/source/_images/fittrackee_screenshot-01.png) ![FitTrackee Dashboard Screenshot](https://samr1.github.io/FitTrackee/_images/fittrackee_screenshot-01.png)
--- ---

View File

@ -1 +1 @@
0.3.0-beta 0.4.0

View File

@ -1,59 +0,0 @@
version: '3.3'
services:
fittrackee-db:
container_name: fittrackee-db
build: https://github.com/SamR1/FitTrackee.git#${BRANCH}:fittrackee_api/db
ports:
- 5435:5432
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
fittrackee-api:
container_name: fittrackee-api
build: https://github.com/SamR1/FitTrackee.git#${BRANCH}:fittrackee_api
ports:
- 5001:5000
environment:
- DATABASE_URL=postgres://postgres:postgres@fittrackee-db:5432/fittrackee
- DATABASE_TEST_URL=postgres://postgres:postgres@fittrackee-db:5432/fittrackee_test
- UI_URL=http://127.0.0.1:3000
- EMAIL_URL=smtp://none:none@0.0.0.0:1025
- SENDER_EMAIL=fittrackee@example.com
- FLASK_APP=server.py
- FLASK_DEBUG=1
- APP_SETTINGS=fittrackee_api.config.TestingConfig
depends_on:
- fittrackee-db
links:
- fittrackee-db
fittrackee-client:
container_name: fittrackee-client
build:
context: https://github.com/SamR1/FitTrackee.git#${BRANCH}
dockerfile: ./fittrackee_client/Dockerfile
args:
- NODE_ENV=development
- REACT_APP_API_URL=${REACT_APP_API_URL}
- CI=true
ports:
- 3007:3000
depends_on:
- fittrackee-api
links:
- fittrackee-api
nginx:
container_name: nginx
build: ./nginx
restart: always
ports:
- 80:80
depends_on:
- fittrackee-api
- fittrackee-client
links:
- fittrackee-api

View File

@ -1,58 +0,0 @@
version: '3.3'
services:
fittrackee-db:
container_name: fittrackee-db
build: ./fittrackee_api/db
ports:
- 5435:5432
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
fittrackee-api:
container_name: fittrackee-api
build: ./fittrackee_api
ports:
- 5001:5000
environment:
- DATABASE_URL=postgres://postgres:postgres@fittrackee-db:5432/fittrackee
- DATABASE_TEST_URL=postgres://postgres:postgres@fittrackee-db:5432/fittrackee_test
- UI_URL=http://127.0.0.1:3000
- EMAIL_URL=smtp://none:none@0.0.0.0:1025
- SENDER_EMAIL=fittrackee@example.com
- FLASK_APP=server.py
- FLASK_DEBUG=1
- APP_SETTINGS=fittrackee_api.config.DevelopmentConfig
depends_on:
- fittrackee-db
links:
- fittrackee-db
fittrackee-client:
container_name: fittrackee-client
build:
context: ./
dockerfile: ./fittrackee_client/Dockerfile
args:
- NODE_ENV=development
- REACT_APP_API_URL=${REACT_APP_API_URL}
ports:
- 3007:3000
depends_on:
- fittrackee-api
links:
- fittrackee-api
nginx:
container_name: nginx
build: ./nginx
restart: always
ports:
- 80:80
depends_on:
- fittrackee-api
- fittrackee-client
links:
- fittrackee-api

View File

@ -1,4 +1,4 @@
# Sphinx build info version 1 # Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 34499f264a902c7412afeba2617f15cb config: 3bbd9f6e4f2cf4ec861ef46913ee1f93
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 KiB

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 KiB

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -1,7 +1,7 @@
Activities Activities
########## ##########
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
activities.get_activities, activities.get_activities,
activities.get_activity, activities.get_activity,

View File

@ -1,7 +1,7 @@
Authentication Authentication
############## ##############
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
auth.register_user, auth.register_user,
auth.login_user, auth.login_user,

View File

@ -1,7 +1,7 @@
Configuration Configuration
############# #############
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
config.get_application_config, config.get_application_config,
config.update_application_config, config.update_application_config,

View File

@ -1,6 +1,6 @@
Records Records
####### #######
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
records.get_records records.get_records

View File

@ -1,7 +1,7 @@
Sports Sports
###### ######
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
sports.get_sports, sports.get_sports,
sports.get_sport, sports.get_sport,

View File

@ -1,7 +1,7 @@
Statistics Statistics
########## ##########
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
stats.get_activities_by_time, stats.get_activities_by_time,
stats.get_activities_by_sport, stats.get_activities_by_sport,

View File

@ -1,7 +1,7 @@
Users Users
##### #####
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
users.get_users, users.get_users,
users.get_single_user, users.get_single_user,

View File

@ -1,14 +1,21 @@
# Change log # Change log
## Version 0.x.x (unreleased) ## Version 0.4.0 (unreleased)
This version introduces some major changes:
- Installation becomes more easy.
⚠️ Warning: please read [installation documentation](https://samr1.github.io/FitTrackee/installation.html), some environment variables and files have been renamed.
- It's now possible to change the tile provider for maps. The default tile server is now **OpenStreetMap**'s standard tile layer (replacing **ThunderForest Outdoors**),
see [Map tile server in documentation](https://samr1.github.io/FitTrackee/installation.html#map-tile-server).
### Issues Closed ### Issues Closed
#### New Features #### New Features
* [#54](https://github.com/SamR1/Fittrackee/issues/54) - Tile server can be changed * [#54](https://github.com/SamR1/Fittrackee/issues/54) - Tile server can be changed
* [#53](https://github.com/SamR1/Fittrackee/issues/53) - Simplify FitTrackee installation
In this release 1 issue weas closed. In this release 2 issue were closed.
## Version 0.3.0 - Administration (2020/07/15) ## Version 0.3.0 - Administration (2020/07/15)

View File

@ -4,13 +4,10 @@ Features
List List
~~~~ ~~~~
Account
^^^^^^^
- A user can create, update and deleted his account
- Password reset is now available
Administration Administration
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
(*new in 0.3.0*)
- **Application** - **Application**
The following parameters can be set: The following parameters can be set:
@ -30,6 +27,12 @@ Administration
- enable or disable a sport (a sport can be disabled even if activity with this sport exists) - enable or disable a sport (a sport can be disabled even if activity with this sport exists)
Account
^^^^^^^
- A user can create, update and deleted his account
- A user can reset his password (*new in 0.3.0*)
Activities/Workouts Activities/Workouts
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
- 6 sports supported: - 6 sports supported:

View File

@ -22,7 +22,7 @@ FitTrackee
Map <https://www.openstreetmap.org>`__. Map <https://www.openstreetmap.org>`__.
| It is also possible to add a workout without a gpx file. | It is also possible to add a workout without a gpx file.
| **Still under development (not ready for production).** | **Still under heavy development (some features may be unstable).**
| (see `issues <https://github.com/SamR1/FitTrackee/issues>`__ for more information) | (see `issues <https://github.com/SamR1/FitTrackee/issues>`__ for more information)
.. figure:: _images/fittrackee_screenshot-01.png .. figure:: _images/fittrackee_screenshot-01.png

View File

@ -22,194 +22,221 @@ Prerequisites
- PostgreSQL database (10+) - PostgreSQL database (10+)
- Redis for task queue - Redis for task queue
- Python 3.7+ - Python 3.7+
- `Poetry <https://poetry.eustace.io>`__ - `Poetry <https://poetry.eustace.io>`__ (for installation from sources only)
- `Yarn <https://yarnpkg.com>`__ and
`serve <https://github.com/zeit/serve>`__
- API key from `Dark Sky <https://darksky.net/dev>`__ [not mandatory] - API key from `Dark Sky <https://darksky.net/dev>`__ [not mandatory]
- SMTP provider - SMTP provider
- `Yarn <https://yarnpkg.com>`__ (for development only)
- Docker (for development only, to start `MailHog <https://github.com/mailhog/MailHog>`__)
.. note::
Installation | The following steps describe an installation on Linux systems (tested
~~~~~~~~~~~~
| The following steps describe an installation on Linux systems (tested
on Debian and Arch). on Debian and Arch).
| On other OS, some issues can be encountered and adaptations may be | On other OS, some issues can be encountered and adaptations may be
necessary. necessary.
.. warning::
Since FitTrackee 0.2.1, Python packages installation needs Poetry. To install it on ArchLinux:
.. code-block:: bash
$ yay poetry
$ poetry --version
Poetry 1.0.5
# optional
$ poetry config virtualenvs.in-project true
For other OS, see `Poetry Documentation <https://python-poetry.org/docs/#installation>`__
Dev environment
^^^^^^^^^^^^^^^
- Clone this repo:
.. code:: bash
$ git clone https://github.com/SamR1/FitTrackee.git
$ cd FitTrackee
- Update **Makefile.config** file if needed and copy/paste the
**ThunderForest** and **Dark Sky** API keys value in
**Makefile.custom.config** file (see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv, React and all related packages and
initialize the database:
.. code:: bash
$ make install-dev
$ make install-db
- Start the server and the client:
.. code:: bash
$ make serve
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Open http://localhost:3000 and login (the email is ``admin@example.com``
and the password ``mpwoadmin``) or register
Prod environment
^^^^^^^^^^^^^^^^
.. warning::
Note that FitTrackee is not production-ready yet
- Download the last release (for now, it is the beta release v0.3.0):
.. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.3.0-beta.tar.gz
$ tar -xzf v0.3.0-beta.tar.gz
$ mv FitTrackee-0.3.0-beta FitTrackee
$ cd FitTrackee
- Update **Makefile.config** file if needed and copy/paste the
**ThunderForest** and **Dark Sky** API keys value in
**Makefile.custom.config** file (see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv, React and all related packages and
initialize the database:
.. code:: bash
$ make install
$ make install-db
- Build the client:
.. code:: bash
$ make build-client
- Start the server and the client:
.. code:: bash
$ make run
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Open http://localhost:3000, log in as admin (the email is
``admin@example.com`` and the password ``mpwoadmin``) and change the
password
Upgrade
~~~~~~~
.. warning::
| Before upgrading, make a backup of all data:
| - database (with `pg_dump <https://www.postgresql.org/docs/11/app-pgdump.html>`__ for instance)
| - upload directory: **FitTrackee/fittrackee_api/fittrackee_api/uploads/**
Dev environment
^^^^^^^^^^^^^^^
- Stop the application and pull the repository:
.. code:: bash
$ git pull
- Update **Makefile.config** and **Makefile.custom.config** file if needed
- Upgrade packages and database:
.. code:: bash
$ make install-dev
$ make upgrade-db
- Restart the server and the client:
.. code:: bash
$ make serve
Prod environment
^^^^^^^^^^^^^^^^
``TODO``
Environment variables Environment variables
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
The following environment variables must be defined in **Makefile.custom.config**: .. warning::
| Since FitTrackee 0.4.0, ``Makefile.custom.config`` is replaced by ``.env``
.. cssclass:: table-bordered table-striped The following environment variables are used by **FitTrackee** web application
or the task processing library. They are not all mandatory depending on
deployment method.
===================================== ============================================== ==================================== .. envvar:: FLASK_APP
variable description app default value
===================================== ============================================== ==================================== | Name of the module to import at flask run.
``REACT_APP_API_URL`` Fittrackee API URL no default value, must be initialized | ``FLASK_APP`` should contain ``$(PWD)/fittrackee/__main__.py`` with installation from sources, else ``fittrackee``.
``REACT_APP_GPX_LIMIT_IMPORT`` max. number of gpx file in zip archive 10 (*deprecated in 0.3.0*)
``REACT_APP_MAX_SINGLE_FILE_SIZE`` max. size of a gpx or picture file 1MB (*deprecated in 0.3.0*)
``REACT_APP_MAX_ZIP_FILE_SIZE`` max. size of a zip archive 10MB (*deprecated in 0.3.0*) .. envvar:: HOST
``REACT_APP_ALLOW_REGISTRATION`` allows users to register true (*deprecated in 0.3.0*)
``REACT_APP_THUNDERFOREST_API_KEY`` ThunderForest API key (*deprecated in 0.x.x*, use ``TILE_SERVER_URL`` **and** ``MAP_ATTRIBUTION`` instead) **FitTrackee** host.
``TILE_SERVER_URL`` Tile server URL (with api key if needed) ``https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png``
``MAP_ATTRIBUTION`` Map attribution (if using another tile server) ``&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`` :default: 0.0.0.0
``UI_URL`` application URL no default value, must be initialized
``EMAIL_URL`` email URL with credentials no default value, must be initialized (see below)
``SENDER_EMAIL`` application sender email address no default value, must be initialized .. envvar:: PORT
``REDIS_URL`` Redis instance used by Dramatiq local Redis instance
``WORKERS_PROCESSES`` number of process used by Dramatiq no default value, must be initialized **FitTrackee** port.
===================================== ============================================== ====================================
:default: 5000
.. envvar:: APP_SETTINGS
**FitTrackee** configuration.
:default: fittrackee.config.ProductionConfig
.. envvar:: APP_SECRET_KEY
**FitTrackee** secret key, must be initialized in production environment.
.. envvar:: APP_WORKERS
Number of workers spawned by **Gunicorn**.
:default: 1
.. envvar:: APP_LOG 🆕
.. versionadded:: 0.4.0
Path to log file
.. envvar:: UPLOAD_FOLDER 🆕
.. versionadded:: 0.4.0
Directory containing uploaded files.
:default: `fittrackee/uploads/`
.. danger::
| With installation from PyPI, the directory will be located in
**virtualenv** directory if the variable is not initialized.
.. envvar:: DATABASE_URL
| Database URL with username and password, must be initialized in production environment.
| For example in dev environment : ``postgres://fittrackee:fittrackee@localhost:5432/fittrackee``
.. envvar:: DATABASE_DISABLE_POOLING 🆕
.. versionadded:: 0.4.0
Disable pooling if needed (when starting application with **FitTrackee** entry point and not directly with **Gunicorn**),
see `SqlAlchemy documentation <https://docs.sqlalchemy.org/en/13/core/pooling.html#using-connection-pools-with-multiprocessing-or-os-fork>`__.
:default: false
.. envvar:: UI_URL
**FitTrackee** URL, needed for links in emails.
.. envvar:: EMAIL_URL
.. versionadded:: 0.3.0
Email URL with credentials, see `Emails <installation.html#emails>`__.
.. envvar:: SENDER_EMAIL
.. versionadded:: 0.3.0
**FitTrackee** sender email address.
.. envvar:: REDIS_URL
.. versionadded:: 0.3.0
Redis instance used by **Dramatiq**.
:default: local Redis instance (``redis://``)
.. envvar:: WORKERS_PROCESSES
.. versionadded:: 0.3.0
Number of processes used by **Dramatiq**.
.. envvar:: TILE_SERVER_URL 🆕
.. versionadded:: 0.4.0
Tile server URL (with api key if needed), see `Map tile server <installation.html#map-tile-server>`__.
:default: `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`
.. envvar:: MAP_ATTRIBUTION 🆕
.. versionadded:: 0.4.0
Map attribution (if using another tile server), see `Map tile server <installation.html#map-tile-server>`__.
:default: `&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`
.. envvar:: WEATHER_API_KEY
.. versionchanged:: 0.4.0 ⚠️ replaces ``WEATHER_API``
**Dark Sky** API key for weather data (not mandatory).
.. envvar:: REACT_APP_API_URL
**FitTrackee** API URL, only needed in dev environment.
Deprecated variables
^^^^^^^^^^^^^^^^^^^^
.. envvar:: REACT_APP_GPX_LIMIT_IMPORT
.. deprecated:: 0.3.0 now stored in database
Maximum number of gpx file in zip archive.
:default: 10
.. envvar:: REACT_APP_MAX_SINGLE_FILE_SIZE
.. deprecated:: 0.3.0 now stored in database
Maximum size of a gpx or picture file.
:default: 1MB
.. envvar:: REACT_APP_MAX_ZIP_FILE_SIZE
.. deprecated:: 0.3.0 now stored in database
Maximum size of a zip archive.
:default: 10MB
.. envvar:: REACT_APP_ALLOW_REGISTRATION
.. deprecated:: 0.3.0 now stored in database
Allows users to register.
:default: true
.. envvar:: REACT_APP_THUNDERFOREST_API_KEY
.. deprecated:: 0.4.0 see `TILE_SERVER_URL <installation.html#envvar-TILE_SERVER_URL>`__
ThunderForest API key.
.. warning:: .. warning::
Since FitTrackee 0.3.0, some applications parameters are now stored in database. | Since FitTrackee 0.3.0, some applications parameters are now stored in database.
Related environment variables are needed to initialize database. | Related environment variables are needed to initialize database when upgrading from version prior 0.3.0.
Emails Emails
^^^^^^ ^^^^^^
*new in 0.3.0* .. versionadded:: 0.3.0
To send emails, a valid ``EMAIL_URL`` must be provided: To send emails, a valid ``EMAIL_URL`` must be provided:
@ -220,15 +247,392 @@ To send emails, a valid ``EMAIL_URL`` must be provided:
Map tile server Map tile server
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
*new in 0.x.x* .. versionadded:: 0.4.0
Default tile server is now **OpenStreetMap**'s standard tile layer (if environment variables are not initialized). Default tile server is now **OpenStreetMap**'s standard tile layer (if environment variables are not initialized).
The tile server can be changed by updating ``TILE_SERVER_URL`` and ``MAP_ATTRIBUTION`` variables (`list of tile servers <https://wiki.openstreetmap.org/wiki/Tile_servers>`__). The tile server can be changed by updating ``TILE_SERVER_URL`` and ``MAP_ATTRIBUTION`` variables (`list of tile servers <https://wiki.openstreetmap.org/wiki/Tile_servers>`__).
To keep using ThunderForest Outdoors, the configuration is: To keep using **ThunderForest Outdoors**, the configuration is:
- ``TILE_SERVER_URL=https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=XXXX`` where **XXXX** is ThunderForest API key - ``TILE_SERVER_URL=https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=XXXX`` where **XXXX** is **ThunderForest** API key
- ``MAP_ATTRIBUTION=&copy; <a href="http://www.thunderforest.com/">Thunderforest</a>, &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`` - ``MAP_ATTRIBUTION=&copy; <a href="http://www.thunderforest.com/">Thunderforest</a>, &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors``
.. note:: .. note::
Check the terms of service of tile provider for map attribution | Check the terms of service of tile provider for map attribution
From PyPI
~~~~~~~~~
.. note::
| Recommended way on production.
.. warning::
| Note that FitTrackee is under heavy development, some features may be unstable.
Installation
^^^^^^^^^^^^
- Create and activate a virtualenv
- Install **FitTrackee** with pip
.. code-block:: bash
$ pip install fittrackee
- Create ``fittrackee`` database
Example :
.. code-block:: sql
CREATE DATABASE fittrackee;
CREATE USER fittrackee WITH PASSWORD '<PASSWORD>';
GRANT ALL PRIVILEGES ON DATABASE fittrackee TO fittrackee;
- Initialize environment variables, see `Environment variables <installation.html#environment-variables>`__
For instance, copy and update ``.env`` file from ``.env.example`` and source the file.
.. code-block:: bash
$ nano .env
$ source .env
- Upgrade database schema
.. code-block:: bash
$ fittrackee_upgrade_db
- Initialize database
.. code-block:: bash
$ fittrackee_init_data
- Start the application
.. code-block:: bash
$ fittrackee
- Start task queue workers
.. code-block:: bash
$ fittrackee_worker --processes 2
.. note::
| To start application and workers with **systemd** service, see `Deployment <installation.html#deployment>`__
Upgrade
^^^^^^^
.. warning::
| Before upgrading, make a backup of all data:
| - database (with `pg_dump <https://www.postgresql.org/docs/11/app-pgdump.html>`__ for instance)
| - upload directory (see `Environment variables <installation.html#environment-variables>`__)
- Activate the virtualenv
- Upgrade with pip
.. code-block:: bash
$ pip install -U fittrackee
- Update environment variables if needed and source environment variables file
.. code-block:: bash
$ nano .env
$ source .env
- Upgrade database if needed
.. code-block:: bash
$ fittrackee_upgrade_db
- Restart the application and task queue workers.
From sources
~~~~~~~~~~~~~
.. warning::
| Since FitTrackee 0.2.1, Python packages installation needs Poetry.
| To install it on ArchLinux:
.. code-block:: bash
$ yay poetry
$ poetry --version
Poetry 1.0.10
# optional
$ poetry config virtualenvs.in-project true
For other OS, see `Poetry Documentation <https://python-poetry.org/docs/#installation>`__
Installation
^^^^^^^^^^^^
Dev environment
"""""""""""""""
- Clone this repo:
.. code:: bash
$ git clone https://github.com/SamR1/FitTrackee.git
$ cd FitTrackee
- Create **Makefile.custom.config** from example and update it
(see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv, React and all related packages and
initialize the database:
.. code:: bash
$ make install-dev
$ make install-db
- Start the server and the client:
.. code:: bash
$ make serve
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Open http://localhost:3000 and log in (the email is ``admin@example.com``
and the password ``mpwoadmin``) or register
Production environment
""""""""""""""""""""""
.. warning::
| Note that FitTrackee is under heavy development, some features may be unstable.
- Download the last release (for now, it is the release v0.4.0):
.. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.4.0.tar.gz
$ tar -xzf v0.4.0.tar.gz
$ mv FitTrackee-0.4.0 FitTrackee
$ cd FitTrackee
- Create **Makefile.custom.config** from example and update it
(see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv and all related packages:
.. code:: bash
$ make install-python
- Initialize the database (**after updating** ``db/create.sql`` **to change
database credentials**):
.. code:: bash
$ make install-db
- Start the server and dramatiq workers:
.. code:: bash
$ make run
Open http://localhost:5000, log in as admin (the email is
``admin@example.com`` and the password ``mpwoadmin``) and change the
password
Upgrade
^^^^^^^
.. warning::
| Before upgrading, make a backup of all data:
| - database (with `pg_dump <https://www.postgresql.org/docs/11/app-pgdump.html>`__ for instance)
| - upload directory (see `Environment variables <installation.html#environment-variables>`__)
Dev environment
"""""""""""""""
- Stop the application and pull the repository:
.. code:: bash
$ git pull
- Update **.env** if needed
- Upgrade packages and database:
.. code:: bash
$ make install-dev
$ make upgrade-db
- Restart the server:
.. code:: bash
$ make serve
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Prod environment
""""""""""""""""
- Stop the application and pull the repository:
.. code:: bash
$ git pull
- Update **Makefile.custom.config** if needed
- Upgrade packages and database:
.. code:: bash
$ make install
$ make upgrade-db
- Restart the server and dramatiq workers:
.. code:: bash
$ make run
Deployment
~~~~~~~~~~~~~
There are several ways to start **FitTrackee** web application and task queue
library.
One way is to use a **systemd** services and **Nginx** to proxy pass to **Gunicorn**.
Examples (to update depending on your application configuration and given distribution):
- for application: ``fittrackee.service``
.. code-block::
[Unit]
Description=FitTrackee service
After=network.target
After=postgresql.service
After=redis.service
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=<USER>
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=fittrackee
Environment="APP_SECRET_KEY="
Environment="APP_LOG="
Environment="UPLOAD_FOLDER="
Environment="DATABASE_URL="
Environment="UI_URL="
Environment="EMAIL_URL="
Environment="SENDER_EMAIL="
Environment="REDIS_URL="
Environment="TILE_SERVER_URL="
Environment="MAP_ATTRIBUTION="
Environment="WEATHER_API_KEY="
WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY>
ExecStart=/home/<USER>/<FITTRACKEE DIRECTORY>/.venv/bin/gunicorn -b 127.0.0.1:5000 "fittrackee:create_app()" --error-logfile /home/<USER>/<FITTRACKEE DIRECTORY>/gunicorn.log
Restart=always
[Install]
WantedBy=multi-user.target
- for task queue workers: ``fittrackee_workers.service``
.. code-block::
[Unit]
Description=FitTrackee task queue service
After=network.target
After=postgresql.service
After=redis.service
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=<USER>
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=fittrackee_workers
Environment="FLASK_APP=fittrackee"
Environment="APP_SECRET_KEY="
Environment="APP_LOG="
Environment="UPLOAD_FOLDER="
Environment="DATABASE_URL="
Environment="UI_URL="
Environment="EMAIL_URL="
Environment="SENDER_EMAIL="
Environment="REDIS_URL="
WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY>
ExecStart=/home/<USER>/<FITTRACKEE DIRECTORY>/.venv/bin/flask worker --processes <NUMBER OF PROCESSES>
Restart=always
[Install]
WantedBy=multi-user.target
- **Nginx** configuration:
.. code-block::
server {
listen 443 ssl;
server_name example.com;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
server {
listen 80;
server_name example.com;
location / {
return 301 https://example.com$request_uri;
}
}
.. note::
More information on `Gunicorn documentation <https://docs.gunicorn.org/en/stable/deploy.html>`__

View File

@ -54,18 +54,37 @@ body {
} }
.alert-danger { .alert-danger {
background-color: #dc6460; background-color: #f2dede;
border-color: transparent; border-color: #dca7a7;
color: #a94442;
} }
.alert-info { .alert-info {
background-color: #3eb3e3; background-color: #d9edf7;
border-color: transparent; border-color: #9acfea;
color: #31708f;
} }
.alert-warning { .alert-warning {
background-color: #f5894f; background-color: #fcf8e3;
border-color: transparent; border-color: #f5e79e;
color: #8a6d3b;
}
.descname {
border-top: solid 3px #a18bac;
border-radius: unset;
padding: 6px;
}
dl.field-list > dt {
background: #f0f0f0;
border-left: solid 3px #ccc;
color: #555;
}
.envvar {
margin-top: 30px;
} }
.footer { .footer {

View File

@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.3.0-beta', VERSION: '0.4.0',
LANGUAGE: 'None', LANGUAGE: 'None',
COLLAPSE_INDEX: false, COLLAPSE_INDEX: false,
BUILDER: 'html', BUILDER: 'html',

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Activities &#8212; FitTrackee 0.3.0-beta <title>Activities &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Authentication &#8212; FitTrackee 0.3.0-beta <title>Authentication &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Configuration &#8212; FitTrackee 0.3.0-beta <title>Configuration &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">
@ -145,7 +146,8 @@
<span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span> <span class="mi">1048576</span><span class="p">,</span> <span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span> <span class="mi">1048576</span><span class="p">,</span>
<span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span> <span class="mi">10485760</span><span class="p">,</span> <span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span> <span class="mi">10485760</span><span class="p">,</span>
<span class="nt">&quot;max_users&quot;</span><span class="p">:</span> <span class="mi">0</span> <span class="nt">&quot;max_users&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span> <span class="s2">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span>
<span class="p">},</span> <span class="p">},</span>
<span class="nt">&quot;status&quot;</span><span class="p">:</span> <span class="s2">&quot;success&quot;</span> <span class="nt">&quot;status&quot;</span><span class="p">:</span> <span class="s2">&quot;success&quot;</span>
<span class="p">}</span> <span class="p">}</span>

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>API documentation &#8212; FitTrackee 0.3.0-beta <title>API documentation &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Records &#8212; FitTrackee 0.3.0-beta <title>Records &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sports &#8212; FitTrackee 0.3.0-beta <title>Sports &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Statistics &#8212; FitTrackee 0.3.0-beta <title>Statistics &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Users &#8212; FitTrackee 0.3.0-beta <title>Users &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Change log &#8212; FitTrackee 0.3.0-beta <title>Change log &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -39,7 +39,8 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">
@ -76,7 +77,7 @@
role="menu" role="menu"
aria-labelledby="dLabelLocalToc"><ul> aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Change log</a><ul> <li><a class="reference internal" href="#">Change log</a><ul>
<li><a class="reference internal" href="#version-0-x-x-unreleased">Version 0.x.x (unreleased)</a><ul> <li><a class="reference internal" href="#version-0-4-0-unreleased">Version 0.4.0 (unreleased)</a><ul>
<li><a class="reference internal" href="#issues-closed">Issues Closed</a><ul> <li><a class="reference internal" href="#issues-closed">Issues Closed</a><ul>
<li><a class="reference internal" href="#new-features">New Features</a></li> <li><a class="reference internal" href="#new-features">New Features</a></li>
</ul> </ul>
@ -195,16 +196,23 @@
<div class="section" id="change-log"> <div class="section" id="change-log">
<h1>Change log<a class="headerlink" href="#change-log" title="Permalink to this headline"></a></h1> <h1>Change log<a class="headerlink" href="#change-log" title="Permalink to this headline"></a></h1>
<div class="section" id="version-0-x-x-unreleased"> <div class="section" id="version-0-4-0-unreleased">
<h2>Version 0.x.x (unreleased)<a class="headerlink" href="#version-0-x-x-unreleased" title="Permalink to this headline"></a></h2> <h2>Version 0.4.0 (unreleased)<a class="headerlink" href="#version-0-4-0-unreleased" title="Permalink to this headline"></a></h2>
<p>This version introduces some major changes:</p>
<ul class="simple">
<li><p>Installation becomes more easy.<br />⚠️ Warning: please read <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html">installation documentation</a>, some environment variables and files have been renamed.</p></li>
<li><p>Its now possible to change the tile provider for maps. The default tile server is now <strong>OpenStreetMap</strong>s standard tile layer (replacing <strong>ThunderForest Outdoors</strong>),
see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#map-tile-server">Map tile server in documentation</a>.</p></li>
</ul>
<div class="section" id="issues-closed"> <div class="section" id="issues-closed">
<h3>Issues Closed<a class="headerlink" href="#issues-closed" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#issues-closed" title="Permalink to this headline"></a></h3>
<div class="section" id="new-features"> <div class="section" id="new-features">
<h4>New Features<a class="headerlink" href="#new-features" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#new-features" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/54">#54</a> - Tile server can be changed</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/54">#54</a> - Tile server can be changed</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/53">#53</a> - Simplify FitTrackee installation</p></li>
</ul> </ul>
<p>In this release 1 issue weas closed.</p> <p>In this release 2 issue were closed.</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Features &#8212; FitTrackee 0.3.0-beta <title>Features &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">
@ -78,8 +79,8 @@
aria-labelledby="dLabelLocalToc"><ul> aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Features</a><ul> <li><a class="reference internal" href="#">Features</a><ul>
<li><a class="reference internal" href="#list">List</a><ul> <li><a class="reference internal" href="#list">List</a><ul>
<li><a class="reference internal" href="#account">Account</a></li>
<li><a class="reference internal" href="#administration">Administration</a></li> <li><a class="reference internal" href="#administration">Administration</a></li>
<li><a class="reference internal" href="#account">Account</a></li>
<li><a class="reference internal" href="#activities-workouts">Activities/Workouts</a></li> <li><a class="reference internal" href="#activities-workouts">Activities/Workouts</a></li>
<li><a class="reference internal" href="#translations">Translations</a></li> <li><a class="reference internal" href="#translations">Translations</a></li>
</ul> </ul>
@ -142,15 +143,9 @@
<h1>Features<a class="headerlink" href="#features" title="Permalink to this headline"></a></h1> <h1>Features<a class="headerlink" href="#features" title="Permalink to this headline"></a></h1>
<div class="section" id="list"> <div class="section" id="list">
<h2>List<a class="headerlink" href="#list" title="Permalink to this headline"></a></h2> <h2>List<a class="headerlink" href="#list" title="Permalink to this headline"></a></h2>
<div class="section" id="account">
<h3>Account<a class="headerlink" href="#account" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>A user can create, update and deleted his account</p></li>
<li><p>Password reset is now available</p></li>
</ul>
</div>
<div class="section" id="administration"> <div class="section" id="administration">
<h3>Administration<a class="headerlink" href="#administration" title="Permalink to this headline"></a></h3> <h3>Administration<a class="headerlink" href="#administration" title="Permalink to this headline"></a></h3>
<p>(<em>new in 0.3.0</em>)</p>
<ul> <ul>
<li><p><strong>Application</strong></p> <li><p><strong>Application</strong></p>
<p>The following parameters can be set:</p> <p>The following parameters can be set:</p>
@ -175,6 +170,13 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="account">
<h3>Account<a class="headerlink" href="#account" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>A user can create, update and deleted his account</p></li>
<li><p>A user can reset his password (<em>new in 0.3.0</em>)</p></li>
</ul>
</div>
<div class="section" id="activities-workouts"> <div class="section" id="activities-workouts">
<h3>Activities/Workouts<a class="headerlink" href="#activities-workouts" title="Permalink to this headline"></a></h3> <h3>Activities/Workouts<a class="headerlink" href="#activities-workouts" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; FitTrackee 0.3.0-beta <title>Index &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -38,7 +38,8 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">
@ -111,8 +112,68 @@
<h1 id="index">Index</h1> <h1 id="index">Index</h1>
<div class="genindex-jumpbox"> <div class="genindex-jumpbox">
<a href="#E"><strong>E</strong></a>
</div> </div>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
environment variable
<ul>
<li><a href="installation.html#envvar-APP_LOG">APP_LOG 🆕</a>
</li>
<li><a href="installation.html#envvar-APP_SECRET_KEY">APP_SECRET_KEY</a>
</li>
<li><a href="installation.html#envvar-APP_SETTINGS">APP_SETTINGS</a>
</li>
<li><a href="installation.html#envvar-APP_WORKERS">APP_WORKERS</a>
</li>
<li><a href="installation.html#envvar-DATABASE_DISABLE_POOLING">DATABASE_DISABLE_POOLING 🆕</a>
</li>
<li><a href="installation.html#envvar-DATABASE_URL">DATABASE_URL</a>
</li>
<li><a href="installation.html#envvar-EMAIL_URL">EMAIL_URL</a>
</li>
<li><a href="installation.html#envvar-FLASK_APP">FLASK_APP</a>
</li>
<li><a href="installation.html#envvar-HOST">HOST</a>
</li>
<li><a href="installation.html#envvar-MAP_ATTRIBUTION">MAP_ATTRIBUTION 🆕</a>
</li>
<li><a href="installation.html#envvar-PORT">PORT</a>
</li>
<li><a href="installation.html#envvar-REACT_APP_ALLOW_REGISTRATION">REACT_APP_ALLOW_REGISTRATION</a>
</li>
<li><a href="installation.html#envvar-REACT_APP_API_URL">REACT_APP_API_URL</a>
</li>
<li><a href="installation.html#envvar-REACT_APP_GPX_LIMIT_IMPORT">REACT_APP_GPX_LIMIT_IMPORT</a>
</li>
<li><a href="installation.html#envvar-REACT_APP_MAX_SINGLE_FILE_SIZE">REACT_APP_MAX_SINGLE_FILE_SIZE</a>
</li>
<li><a href="installation.html#envvar-REACT_APP_MAX_ZIP_FILE_SIZE">REACT_APP_MAX_ZIP_FILE_SIZE</a>
</li>
<li><a href="installation.html#envvar-REACT_APP_THUNDERFOREST_API_KEY">REACT_APP_THUNDERFOREST_API_KEY</a>
</li>
<li><a href="installation.html#envvar-REDIS_URL">REDIS_URL</a>
</li>
<li><a href="installation.html#envvar-SENDER_EMAIL">SENDER_EMAIL</a>
</li>
<li><a href="installation.html#envvar-TILE_SERVER_URL">TILE_SERVER_URL 🆕</a>
</li>
<li><a href="installation.html#envvar-UI_URL">UI_URL</a>
</li>
<li><a href="installation.html#envvar-UPLOAD_FOLDER">UPLOAD_FOLDER 🆕</a>
</li>
<li><a href="installation.html#envvar-WEATHER_API_KEY">WEATHER_API_KEY</a>
</li>
<li><a href="installation.html#envvar-WORKERS_PROCESSES">WORKERS_PROCESSES</a>
</li>
</ul></li>
</ul></td>
</tr></table>
</div> </div>

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HTTP Routing Table &#8212; FitTrackee 0.3.0-beta <title>HTTP Routing Table &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -45,7 +45,8 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>FitTrackee &#8212; FitTrackee 0.3.0-beta <title>FitTrackee &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -39,7 +39,8 @@
</button> </button>
<a class="navbar-brand" href="#"> <a class="navbar-brand" href="#">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">
@ -142,7 +143,7 @@ Map</a>.</div>
<div class="line">It is also possible to add a workout without a gpx file.</div> <div class="line">It is also possible to add a workout without a gpx file.</div>
</div> </div>
<div class="line-block"> <div class="line-block">
<div class="line"><strong>Still under development (not ready for production).</strong></div> <div class="line"><strong>Still under heavy development (some features may be unstable).</strong></div>
<div class="line">(see <a class="reference external" href="https://github.com/SamR1/FitTrackee/issues">issues</a> for more information)</div> <div class="line">(see <a class="reference external" href="https://github.com/SamR1/FitTrackee/issues">issues</a> for more information)</div>
</div> </div>
<div class="figure align-default"> <div class="figure align-default">
@ -155,9 +156,10 @@ Map</a>.</div>
<ul> <ul>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a><ul> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="installation.html#prerequisites">Prerequisites</a></li> <li class="toctree-l2"><a class="reference internal" href="installation.html#prerequisites">Prerequisites</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#id1">Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#upgrade">Upgrade</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#environment-variables">Environment variables</a></li> <li class="toctree-l2"><a class="reference internal" href="installation.html#environment-variables">Environment variables</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#from-pypi">From PyPI</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#from-sources">From sources</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#deployment">Deployment</a></li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a><ul> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a><ul>
@ -185,7 +187,7 @@ Map</a>.</div>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a><ul> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a><ul>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-x-x-unreleased">Version 0.x.x (unreleased)</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-4-0-unreleased">Version 0.4.0 (unreleased)</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-3-0-administration-2020-07-15">Version 0.3.0 - Administration (2020/07/15)</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-3-0-administration-2020-07-15">Version 0.3.0 - Administration (2020/07/15)</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-2-5-fix-and-improvements-2020-01-31">Version 0.2.5 - Fix and improvements (2020/01/31)</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-2-5-fix-and-improvements-2020-01-31">Version 0.2.5 - Fix and improvements (2020/01/31)</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-2-4-minor-fix-2020-01-30">Version 0.2.4 - Minor fix (2020/01/30)</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-2-4-minor-fix-2020-01-30">Version 0.2.4 - Minor fix (2020/01/30)</a></li>

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Installation &#8212; FitTrackee 0.3.0-beta <title>Installation &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">
@ -78,21 +79,31 @@
aria-labelledby="dLabelLocalToc"><ul> aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Installation</a><ul> <li><a class="reference internal" href="#">Installation</a><ul>
<li><a class="reference internal" href="#prerequisites">Prerequisites</a></li> <li><a class="reference internal" href="#prerequisites">Prerequisites</a></li>
<li><a class="reference internal" href="#id1">Installation</a><ul>
<li><a class="reference internal" href="#dev-environment">Dev environment</a></li>
<li><a class="reference internal" href="#prod-environment">Prod environment</a></li>
</ul>
</li>
<li><a class="reference internal" href="#upgrade">Upgrade</a><ul>
<li><a class="reference internal" href="#id2">Dev environment</a></li>
<li><a class="reference internal" href="#id3">Prod environment</a></li>
</ul>
</li>
<li><a class="reference internal" href="#environment-variables">Environment variables</a><ul> <li><a class="reference internal" href="#environment-variables">Environment variables</a><ul>
<li><a class="reference internal" href="#deprecated-variables">Deprecated variables</a></li>
<li><a class="reference internal" href="#emails">Emails</a></li> <li><a class="reference internal" href="#emails">Emails</a></li>
<li><a class="reference internal" href="#map-tile-server">Map tile server</a></li> <li><a class="reference internal" href="#map-tile-server">Map tile server</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#from-pypi">From PyPI</a><ul>
<li><a class="reference internal" href="#id1">Installation</a></li>
<li><a class="reference internal" href="#upgrade">Upgrade</a></li>
</ul>
</li>
<li><a class="reference internal" href="#from-sources">From sources</a><ul>
<li><a class="reference internal" href="#id2">Installation</a><ul>
<li><a class="reference internal" href="#dev-environment">Dev environment</a></li>
<li><a class="reference internal" href="#production-environment">Production environment</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id3">Upgrade</a><ul>
<li><a class="reference internal" href="#id4">Dev environment</a></li>
<li><a class="reference internal" href="#prod-environment">Prod environment</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#deployment">Deployment</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -174,234 +185,316 @@
<li><p>PostgreSQL database (10+)</p></li> <li><p>PostgreSQL database (10+)</p></li>
<li><p>Redis for task queue</p></li> <li><p>Redis for task queue</p></li>
<li><p>Python 3.7+</p></li> <li><p>Python 3.7+</p></li>
<li><p><a class="reference external" href="https://poetry.eustace.io">Poetry</a></p></li> <li><p><a class="reference external" href="https://poetry.eustace.io">Poetry</a> (for installation from sources only)</p></li>
<li><p><a class="reference external" href="https://yarnpkg.com">Yarn</a> and
<a class="reference external" href="https://github.com/zeit/serve">serve</a></p></li>
<li><p>API key from <a class="reference external" href="https://darksky.net/dev">Dark Sky</a> [not mandatory]</p></li> <li><p>API key from <a class="reference external" href="https://darksky.net/dev">Dark Sky</a> [not mandatory]</p></li>
<li><p>SMTP provider</p></li> <li><p>SMTP provider</p></li>
<li><p><a class="reference external" href="https://yarnpkg.com">Yarn</a> (for development only)</p></li>
<li><p>Docker (for development only, to start <a class="reference external" href="https://github.com/mailhog/MailHog">MailHog</a>)</p></li>
</ul> </ul>
</div> <div class="admonition note">
<div class="section" id="id1"> <p class="admonition-title">Note</p>
<h2>Installation<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h2>
<div class="line-block"> <div class="line-block">
<div class="line">The following steps describe an installation on Linux systems (tested <div class="line">The following steps describe an installation on Linux systems (tested
on Debian and Arch).</div> on Debian and Arch).</div>
<div class="line">On other OS, some issues can be encountered and adaptations may be <div class="line">On other OS, some issues can be encountered and adaptations may be
necessary.</div> necessary.</div>
</div> </div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Since FitTrackee 0.2.1, Python packages installation needs Poetry. To install it on ArchLinux:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ yay poetry
$ poetry --version
Poetry <span class="m">1</span>.0.5
<span class="c1"># optional</span>
$ poetry config virtualenvs.in-project <span class="nb">true</span>
</pre></div>
</div>
<p>For other OS, see <a class="reference external" href="https://python-poetry.org/docs/#installation">Poetry Documentation</a></p>
</div>
<div class="section" id="dev-environment">
<h3>Dev environment<a class="headerlink" href="#dev-environment" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Clone this repo:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ git clone https://github.com/SamR1/FitTrackee.git
$ <span class="nb">cd</span> FitTrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Update <strong>Makefile.config</strong> file if needed and copy/paste the
<strong>ThunderForest</strong> and <strong>Dark Sky</strong> API keys value in
<strong>Makefile.custom.config</strong> file (see <a class="reference external" href="installation.html#environment-variables">Environment variables</a>).</p></li>
<li><p>Install Python virtualenv, React and all related packages and
initialize the database:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install-dev
$ make install-db
</pre></div>
</div>
<ul class="simple">
<li><p>Start the server and the client:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make serve
</pre></div>
</div>
<ul class="simple">
<li><p>Run dramatiq workers:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run-workers
</pre></div>
</div>
<p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a> and login (the email is <code class="docutils literal notranslate"><span class="pre">admin&#64;example.com</span></code>
and the password <code class="docutils literal notranslate"><span class="pre">mpwoadmin</span></code>) or register</p>
</div>
<div class="section" id="prod-environment">
<h3>Prod environment<a class="headerlink" href="#prod-environment" title="Permalink to this headline"></a></h3>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Note that FitTrackee is not production-ready yet</p>
</div>
<ul class="simple">
<li><p>Download the last release (for now, it is the beta release v0.3.0):</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.3.0-beta.tar.gz
$ tar -xzf v0.3.0-beta.tar.gz
$ mv FitTrackee-0.3.0-beta FitTrackee
$ <span class="nb">cd</span> FitTrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Update <strong>Makefile.config</strong> file if needed and copy/paste the
<strong>ThunderForest</strong> and <strong>Dark Sky</strong> API keys value in
<strong>Makefile.custom.config</strong> file (see <a class="reference external" href="installation.html#environment-variables">Environment variables</a>).</p></li>
<li><p>Install Python virtualenv, React and all related packages and
initialize the database:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install
$ make install-db
</pre></div>
</div>
<ul class="simple">
<li><p>Build the client:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make build-client
</pre></div>
</div>
<ul class="simple">
<li><p>Start the server and the client:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run
</pre></div>
</div>
<ul class="simple">
<li><p>Run dramatiq workers:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run-workers
</pre></div>
</div>
<p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a>, log in as admin (the email is
<code class="docutils literal notranslate"><span class="pre">admin&#64;example.com</span></code> and the password <code class="docutils literal notranslate"><span class="pre">mpwoadmin</span></code>) and change the
password</p>
</div>
</div>
<div class="section" id="upgrade">
<h2>Upgrade<a class="headerlink" href="#upgrade" title="Permalink to this headline"></a></h2>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Before upgrading, make a backup of all data:</div>
<div class="line">- database (with <a class="reference external" href="https://www.postgresql.org/docs/11/app-pgdump.html">pg_dump</a> for instance)</div>
<div class="line">- upload directory: <strong>FitTrackee/fittrackee_api/fittrackee_api/uploads/</strong></div>
</div>
</div>
<div class="section" id="id2">
<h3>Dev environment<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Stop the application and pull the repository:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ git pull
</pre></div>
</div>
<ul class="simple">
<li><p>Update <strong>Makefile.config</strong> and <strong>Makefile.custom.config</strong> file if needed</p></li>
<li><p>Upgrade packages and database:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install-dev
$ make upgrade-db
</pre></div>
</div>
<ul class="simple">
<li><p>Restart the server and the client:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make serve
</pre></div>
</div>
</div>
<div class="section" id="id3">
<h3>Prod environment<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">TODO</span></code></p>
</div> </div>
</div> </div>
<div class="section" id="environment-variables"> <div class="section" id="environment-variables">
<h2>Environment variables<a class="headerlink" href="#environment-variables" title="Permalink to this headline"></a></h2> <h2>Environment variables<a class="headerlink" href="#environment-variables" title="Permalink to this headline"></a></h2>
<p>The following environment variables must be defined in <strong>Makefile.custom.config</strong>:</p>
<table class="table-bordered table-striped docutils align-default">
<colgroup>
<col style="width: 17%" />
<col style="width: 21%" />
<col style="width: 61%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>variable</p></th>
<th class="head"><p>description</p></th>
<th class="head"><p>app default value</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">REACT_APP_API_URL</span></code></p></td>
<td><p>Fittrackee API URL</p></td>
<td><p>no default value, must be initialized</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">REACT_APP_GPX_LIMIT_IMPORT</span></code></p></td>
<td><p>max. number of gpx file in zip archive</p></td>
<td><p>10 (<em>deprecated in 0.3.0</em>)</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">REACT_APP_MAX_SINGLE_FILE_SIZE</span></code></p></td>
<td><p>max. size of a gpx or picture file</p></td>
<td><p>1MB (<em>deprecated in 0.3.0</em>)</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">REACT_APP_MAX_ZIP_FILE_SIZE</span></code></p></td>
<td><p>max. size of a zip archive</p></td>
<td><p>10MB (<em>deprecated in 0.3.0</em>)</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">REACT_APP_ALLOW_REGISTRATION</span></code></p></td>
<td><p>allows users to register</p></td>
<td><p>true (<em>deprecated in 0.3.0</em>)</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">REACT_APP_THUNDERFOREST_API_KEY</span></code></p></td>
<td><p>ThunderForest API key</p></td>
<td><p>(<em>deprecated in 0.x.x</em>, use <code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL</span></code> <strong>and</strong> <code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION</span></code> instead)</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL</span></code></p></td>
<td><p>Tile server URL (with api key if needed)</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION</span></code></p></td>
<td><p>Map attribution (if using another tile server)</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&amp;copy;</span> <span class="pre">&lt;a</span> <span class="pre">href=&quot;http://www.openstreetmap.org/copyright&quot;</span> <span class="pre">target=&quot;_blank&quot;</span> <span class="pre">rel=&quot;noopener</span> <span class="pre">noreferrer&quot;&gt;OpenStreetMap&lt;/a&gt;</span> <span class="pre">contributors</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">UI_URL</span></code></p></td>
<td><p>application URL</p></td>
<td><p>no default value, must be initialized</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">EMAIL_URL</span></code></p></td>
<td><p>email URL with credentials</p></td>
<td><p>no default value, must be initialized (see below)</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">SENDER_EMAIL</span></code></p></td>
<td><p>application sender email address</p></td>
<td><p>no default value, must be initialized</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">REDIS_URL</span></code></p></td>
<td><p>Redis instance used by Dramatiq</p></td>
<td><p>local Redis instance</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">WORKERS_PROCESSES</span></code></p></td>
<td><p>number of process used by Dramatiq</p></td>
<td><p>no default value, must be initialized</p></td>
</tr>
</tbody>
</table>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<p>Since FitTrackee 0.3.0, some applications parameters are now stored in database. <div class="line-block">
Related environment variables are needed to initialize database.</p> <div class="line">Since FitTrackee 0.4.0, <code class="docutils literal notranslate"><span class="pre">Makefile.custom.config</span></code> is replaced by <code class="docutils literal notranslate"><span class="pre">.env</span></code></div>
</div>
</div>
<p>The following environment variables are used by <strong>FitTrackee</strong> web application
or the task processing library. They are not all mandatory depending on
deployment method.</p>
<dl class="std envvar">
<dt id="envvar-FLASK_APP">
<code class="sig-name descname">FLASK_APP</code><a class="headerlink" href="#envvar-FLASK_APP" title="Permalink to this definition"></a></dt>
<dd><div class="line-block">
<div class="line">Name of the module to import at flask run.</div>
<div class="line"><code class="docutils literal notranslate"><span class="pre">FLASK_APP</span></code> should contain <code class="docutils literal notranslate"><span class="pre">$(PWD)/fittrackee/__main__.py</span></code> with installation from sources, else <code class="docutils literal notranslate"><span class="pre">fittrackee</span></code>.</div>
</div>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-HOST">
<code class="sig-name descname">HOST</code><a class="headerlink" href="#envvar-HOST" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> host.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>0.0.0.0</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-PORT">
<code class="sig-name descname">PORT</code><a class="headerlink" href="#envvar-PORT" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> port.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>5000</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-APP_SETTINGS">
<code class="sig-name descname">APP_SETTINGS</code><a class="headerlink" href="#envvar-APP_SETTINGS" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> configuration.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>fittrackee.config.ProductionConfig</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-APP_SECRET_KEY">
<code class="sig-name descname">APP_SECRET_KEY</code><a class="headerlink" href="#envvar-APP_SECRET_KEY" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> secret key, must be initialized in production environment.</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-APP_WORKERS">
<code class="sig-name descname">APP_WORKERS</code><a class="headerlink" href="#envvar-APP_WORKERS" title="Permalink to this definition"></a></dt>
<dd><p>Number of workers spawned by <strong>Gunicorn</strong>.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>1</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-APP_LOG">
<span id="envvar-APP_LOG 🆕"></span><code class="sig-name descname">APP_LOG 🆕</code><a class="headerlink" href="#envvar-APP_LOG" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div>
<p>Path to log file</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-UPLOAD_FOLDER">
<span id="envvar-UPLOAD_FOLDER 🆕"></span><code class="sig-name descname">UPLOAD_FOLDER 🆕</code><a class="headerlink" href="#envvar-UPLOAD_FOLDER" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div>
<p>Directory containing uploaded files.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p><cite>fittrackee/uploads/</cite></p>
</dd>
</dl>
<div class="admonition danger">
<p class="admonition-title">Danger</p>
<div class="line-block">
<div class="line">With installation from PyPI, the directory will be located in
<strong>virtualenv</strong> directory if the variable is not initialized.</div>
</div>
</div>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-DATABASE_URL">
<code class="sig-name descname">DATABASE_URL</code><a class="headerlink" href="#envvar-DATABASE_URL" title="Permalink to this definition"></a></dt>
<dd><div class="line-block">
<div class="line">Database URL with username and password, must be initialized in production environment.</div>
<div class="line">For example in dev environment : <code class="docutils literal notranslate"><span class="pre">postgres://fittrackee:fittrackee&#64;localhost:5432/fittrackee</span></code></div>
</div>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-DATABASE_DISABLE_POOLING">
<span id="envvar-DATABASE_DISABLE_POOLING 🆕"></span><code class="sig-name descname">DATABASE_DISABLE_POOLING 🆕</code><a class="headerlink" href="#envvar-DATABASE_DISABLE_POOLING" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div>
<p>Disable pooling if needed (when starting application with <strong>FitTrackee</strong> entry point and not directly with <strong>Gunicorn</strong>),
see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/pooling.html#using-connection-pools-with-multiprocessing-or-os-fork">SqlAlchemy documentation</a>.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>false</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-UI_URL">
<code class="sig-name descname">UI_URL</code><a class="headerlink" href="#envvar-UI_URL" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> URL, needed for links in emails.</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-EMAIL_URL">
<code class="sig-name descname">EMAIL_URL</code><a class="headerlink" href="#envvar-EMAIL_URL" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div>
<p>Email URL with credentials, see <a class="reference external" href="installation.html#emails">Emails</a>.</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-SENDER_EMAIL">
<code class="sig-name descname">SENDER_EMAIL</code><a class="headerlink" href="#envvar-SENDER_EMAIL" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div>
<p><strong>FitTrackee</strong> sender email address.</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-REDIS_URL">
<code class="sig-name descname">REDIS_URL</code><a class="headerlink" href="#envvar-REDIS_URL" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div>
<p>Redis instance used by <strong>Dramatiq</strong>.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>local Redis instance (<code class="docutils literal notranslate"><span class="pre">redis://</span></code>)</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-WORKERS_PROCESSES">
<code class="sig-name descname">WORKERS_PROCESSES</code><a class="headerlink" href="#envvar-WORKERS_PROCESSES" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div>
<p>Number of processes used by <strong>Dramatiq</strong>.</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-TILE_SERVER_URL">
<span id="envvar-TILE_SERVER_URL 🆕"></span><code class="sig-name descname">TILE_SERVER_URL 🆕</code><a class="headerlink" href="#envvar-TILE_SERVER_URL" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div>
<p>Tile server URL (with api key if needed), see <a class="reference external" href="installation.html#map-tile-server">Map tile server</a>.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p><cite>https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png</cite></p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-MAP_ATTRIBUTION">
<span id="envvar-MAP_ATTRIBUTION 🆕"></span><code class="sig-name descname">MAP_ATTRIBUTION 🆕</code><a class="headerlink" href="#envvar-MAP_ATTRIBUTION" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div>
<p>Map attribution (if using another tile server), see <a class="reference external" href="installation.html#map-tile-server">Map tile server</a>.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p><cite>&amp;copy; &lt;a href=”http://www.openstreetmap.org/copyright” target=”_blank” rel=”noopener noreferrer”&gt;OpenStreetMap&lt;/a&gt; contributors</cite></p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-WEATHER_API_KEY">
<code class="sig-name descname">WEATHER_API_KEY</code><a class="headerlink" href="#envvar-WEATHER_API_KEY" title="Permalink to this definition"></a></dt>
<dd><div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.4.0: </span>⚠️ replaces <code class="docutils literal notranslate"><span class="pre">WEATHER_API</span></code></p>
</div>
<p><strong>Dark Sky</strong> API key for weather data (not mandatory).</p>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-REACT_APP_API_URL">
<code class="sig-name descname">REACT_APP_API_URL</code><a class="headerlink" href="#envvar-REACT_APP_API_URL" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> API URL, only needed in dev environment.</p>
</dd></dl>
<div class="section" id="deprecated-variables">
<h3>Deprecated variables<a class="headerlink" href="#deprecated-variables" title="Permalink to this headline"></a></h3>
<dl class="std envvar">
<dt id="envvar-REACT_APP_GPX_LIMIT_IMPORT">
<code class="sig-name descname">REACT_APP_GPX_LIMIT_IMPORT</code><a class="headerlink" href="#envvar-REACT_APP_GPX_LIMIT_IMPORT" title="Permalink to this definition"></a></dt>
<dd><div class="deprecated">
<p><span class="versionmodified deprecated">Deprecated since version 0.3.0: </span>now stored in database</p>
</div>
<p>Maximum number of gpx file in zip archive.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>10</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-REACT_APP_MAX_SINGLE_FILE_SIZE">
<code class="sig-name descname">REACT_APP_MAX_SINGLE_FILE_SIZE</code><a class="headerlink" href="#envvar-REACT_APP_MAX_SINGLE_FILE_SIZE" title="Permalink to this definition"></a></dt>
<dd><div class="deprecated">
<p><span class="versionmodified deprecated">Deprecated since version 0.3.0: </span>now stored in database</p>
</div>
<p>Maximum size of a gpx or picture file.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>1MB</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-REACT_APP_MAX_ZIP_FILE_SIZE">
<code class="sig-name descname">REACT_APP_MAX_ZIP_FILE_SIZE</code><a class="headerlink" href="#envvar-REACT_APP_MAX_ZIP_FILE_SIZE" title="Permalink to this definition"></a></dt>
<dd><div class="deprecated">
<p><span class="versionmodified deprecated">Deprecated since version 0.3.0: </span>now stored in database</p>
</div>
<p>Maximum size of a zip archive.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>10MB</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-REACT_APP_ALLOW_REGISTRATION">
<code class="sig-name descname">REACT_APP_ALLOW_REGISTRATION</code><a class="headerlink" href="#envvar-REACT_APP_ALLOW_REGISTRATION" title="Permalink to this definition"></a></dt>
<dd><div class="deprecated">
<p><span class="versionmodified deprecated">Deprecated since version 0.3.0: </span>now stored in database</p>
</div>
<p>Allows users to register.</p>
<dl class="field-list simple">
<dt class="field-odd">Default</dt>
<dd class="field-odd"><p>true</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar">
<dt id="envvar-REACT_APP_THUNDERFOREST_API_KEY">
<code class="sig-name descname">REACT_APP_THUNDERFOREST_API_KEY</code><a class="headerlink" href="#envvar-REACT_APP_THUNDERFOREST_API_KEY" title="Permalink to this definition"></a></dt>
<dd><div class="deprecated">
<p><span class="versionmodified deprecated">Deprecated since version 0.4.0: </span>see <a class="reference external" href="installation.html#envvar-TILE_SERVER_URL">TILE_SERVER_URL</a></p>
</div>
<p>ThunderForest API key.</p>
</dd></dl>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Since FitTrackee 0.3.0, some applications parameters are now stored in database.</div>
<div class="line">Related environment variables are needed to initialize database when upgrading from version prior 0.3.0.</div>
</div>
</div>
</div> </div>
<div class="section" id="emails"> <div class="section" id="emails">
<h3>Emails<a class="headerlink" href="#emails" title="Permalink to this headline"></a></h3> <h3>Emails<a class="headerlink" href="#emails" title="Permalink to this headline"></a></h3>
<p><em>new in 0.3.0</em></p> <div class="versionadded">
<p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div>
<p>To send emails, a valid <code class="docutils literal notranslate"><span class="pre">EMAIL_URL</span></code> must be provided:</p> <p>To send emails, a valid <code class="docutils literal notranslate"><span class="pre">EMAIL_URL</span></code> must be provided:</p>
<ul class="simple"> <ul class="simple">
<li><p>with an unencrypted SMTP server: <code class="docutils literal notranslate"><span class="pre">smtp://username:password&#64;smtp.example.com:25</span></code></p></li> <li><p>with an unencrypted SMTP server: <code class="docutils literal notranslate"><span class="pre">smtp://username:password&#64;smtp.example.com:25</span></code></p></li>
@ -411,20 +504,402 @@ Related environment variables are needed to initialize database.</p>
</div> </div>
<div class="section" id="map-tile-server"> <div class="section" id="map-tile-server">
<h3>Map tile server<a class="headerlink" href="#map-tile-server" title="Permalink to this headline"></a></h3> <h3>Map tile server<a class="headerlink" href="#map-tile-server" title="Permalink to this headline"></a></h3>
<p><em>new in 0.x.x</em></p> <div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div>
<p>Default tile server is now <strong>OpenStreetMap</strong>s standard tile layer (if environment variables are not initialized). <p>Default tile server is now <strong>OpenStreetMap</strong>s standard tile layer (if environment variables are not initialized).
The tile server can be changed by updating <code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL</span></code> and <code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION</span></code> variables (<a class="reference external" href="https://wiki.openstreetmap.org/wiki/Tile_servers">list of tile servers</a>).</p> The tile server can be changed by updating <code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL</span></code> and <code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION</span></code> variables (<a class="reference external" href="https://wiki.openstreetmap.org/wiki/Tile_servers">list of tile servers</a>).</p>
<p>To keep using ThunderForest Outdoors, the configuration is:</p> <p>To keep using <strong>ThunderForest Outdoors</strong>, the configuration is:</p>
<ul class="simple"> <ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL=https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=XXXX</span></code> where <strong>XXXX</strong> is ThunderForest API key</p></li> <li><p><code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL=https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=XXXX</span></code> where <strong>XXXX</strong> is <strong>ThunderForest</strong> API key</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION=&amp;copy;</span> <span class="pre">&lt;a</span> <span class="pre">href=&quot;http://www.thunderforest.com/&quot;&gt;Thunderforest&lt;/a&gt;,</span> <span class="pre">&amp;copy;</span> <span class="pre">&lt;a</span> <span class="pre">href=&quot;http://www.openstreetmap.org/copyright&quot;&gt;OpenStreetMap&lt;/a&gt;</span> <span class="pre">contributors</span></code></p></li> <li><p><code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION=&amp;copy;</span> <span class="pre">&lt;a</span> <span class="pre">href=&quot;http://www.thunderforest.com/&quot;&gt;Thunderforest&lt;/a&gt;,</span> <span class="pre">&amp;copy;</span> <span class="pre">&lt;a</span> <span class="pre">href=&quot;http://www.openstreetmap.org/copyright&quot;&gt;OpenStreetMap&lt;/a&gt;</span> <span class="pre">contributors</span></code></p></li>
</ul> </ul>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Note</p> <p class="admonition-title">Note</p>
<p>Check the terms of service of tile provider for map attribution</p> <div class="line-block">
<div class="line">Check the terms of service of tile provider for map attribution</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="section" id="from-pypi">
<h2>From PyPI<a class="headerlink" href="#from-pypi" title="Permalink to this headline"></a></h2>
<div class="admonition note">
<p class="admonition-title">Note</p>
<div class="line-block">
<div class="line">Recommended way on production.</div>
</div>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Note that FitTrackee is under heavy development, some features may be unstable.</div>
</div>
</div>
<div class="section" id="id1">
<h3>Installation<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Create and activate a virtualenv</p></li>
<li><p>Install <strong>FitTrackee</strong> with pip</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ pip install fittrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Create <code class="docutils literal notranslate"><span class="pre">fittrackee</span></code> database</p></li>
</ul>
<p>Example :</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">fittrackee</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="n">fittrackee</span> <span class="k">WITH</span> <span class="n">PASSWORD</span> <span class="s1">&#39;&lt;PASSWORD&gt;&#39;</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="k">DATABASE</span> <span class="n">fittrackee</span> <span class="k">TO</span> <span class="n">fittrackee</span><span class="p">;</span>
</pre></div>
</div>
<ul class="simple">
<li><p>Initialize environment variables, see <a class="reference external" href="installation.html#environment-variables">Environment variables</a></p></li>
</ul>
<p>For instance, copy and update <code class="docutils literal notranslate"><span class="pre">.env</span></code> file from <code class="docutils literal notranslate"><span class="pre">.env.example</span></code> and source the file.</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ nano .env
$ <span class="nb">source</span> .env
</pre></div>
</div>
<ul class="simple">
<li><p>Upgrade database schema</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_upgrade_db
</pre></div>
</div>
<ul class="simple">
<li><p>Initialize database</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_init_data
</pre></div>
</div>
<ul class="simple">
<li><p>Start the application</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Start task queue workers</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_worker --processes <span class="m">2</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<div class="line-block">
<div class="line">To start application and workers with <strong>systemd</strong> service, see <a class="reference external" href="installation.html#deployment">Deployment</a></div>
</div>
</div>
</div>
<div class="section" id="upgrade">
<h3>Upgrade<a class="headerlink" href="#upgrade" title="Permalink to this headline"></a></h3>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Before upgrading, make a backup of all data:</div>
<div class="line">- database (with <a class="reference external" href="https://www.postgresql.org/docs/11/app-pgdump.html">pg_dump</a> for instance)</div>
<div class="line">- upload directory (see <a class="reference external" href="installation.html#environment-variables">Environment variables</a>)</div>
</div>
</div>
<ul class="simple">
<li><p>Activate the virtualenv</p></li>
<li><p>Upgrade with pip</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ pip install -U fittrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Update environment variables if needed and source environment variables file</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ nano .env
$ <span class="nb">source</span> .env
</pre></div>
</div>
<ul class="simple">
<li><p>Upgrade database if needed</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_upgrade_db
</pre></div>
</div>
<ul class="simple">
<li><p>Restart the application and task queue workers.</p></li>
</ul>
</div>
</div>
<div class="section" id="from-sources">
<h2>From sources<a class="headerlink" href="#from-sources" title="Permalink to this headline"></a></h2>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Since FitTrackee 0.2.1, Python packages installation needs Poetry.</div>
<div class="line">To install it on ArchLinux:</div>
</div>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ yay poetry
$ poetry --version
Poetry <span class="m">1</span>.0.10
<span class="c1"># optional</span>
$ poetry config virtualenvs.in-project <span class="nb">true</span>
</pre></div>
</div>
<p>For other OS, see <a class="reference external" href="https://python-poetry.org/docs/#installation">Poetry Documentation</a></p>
</div>
<div class="section" id="id2">
<h3>Installation<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3>
<div class="section" id="dev-environment">
<h4>Dev environment<a class="headerlink" href="#dev-environment" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p>Clone this repo:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ git clone https://github.com/SamR1/FitTrackee.git
$ <span class="nb">cd</span> FitTrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Create <strong>Makefile.custom.config</strong> from example and update it
(see <a class="reference external" href="installation.html#environment-variables">Environment variables</a>).</p></li>
<li><p>Install Python virtualenv, React and all related packages and
initialize the database:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install-dev
$ make install-db
</pre></div>
</div>
<ul class="simple">
<li><p>Start the server and the client:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make serve
</pre></div>
</div>
<ul class="simple">
<li><p>Run dramatiq workers:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run-workers
</pre></div>
</div>
<p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a> and log in (the email is <code class="docutils literal notranslate"><span class="pre">admin&#64;example.com</span></code>
and the password <code class="docutils literal notranslate"><span class="pre">mpwoadmin</span></code>) or register</p>
</div>
<div class="section" id="production-environment">
<h4>Production environment<a class="headerlink" href="#production-environment" title="Permalink to this headline"></a></h4>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Note that FitTrackee is under heavy development, some features may be unstable.</div>
</div>
</div>
<ul class="simple">
<li><p>Download the last release (for now, it is the release v0.4.0):</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.4.0.tar.gz
$ tar -xzf v0.4.0.tar.gz
$ mv FitTrackee-0.4.0 FitTrackee
$ <span class="nb">cd</span> FitTrackee
</pre></div>
</div>
<ul class="simple">
<li><p>Create <strong>Makefile.custom.config</strong> from example and update it
(see <a class="reference external" href="installation.html#environment-variables">Environment variables</a>).</p></li>
<li><p>Install Python virtualenv and all related packages:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install-python
</pre></div>
</div>
<ul class="simple">
<li><p>Initialize the database (<strong>after updating</strong> <code class="docutils literal notranslate"><span class="pre">db/create.sql</span></code> <strong>to change
database credentials</strong>):</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install-db
</pre></div>
</div>
<ul class="simple">
<li><p>Start the server and dramatiq workers:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run
</pre></div>
</div>
<p>Open <a class="reference external" href="http://localhost:5000">http://localhost:5000</a>, log in as admin (the email is
<code class="docutils literal notranslate"><span class="pre">admin&#64;example.com</span></code> and the password <code class="docutils literal notranslate"><span class="pre">mpwoadmin</span></code>) and change the
password</p>
</div>
</div>
<div class="section" id="id3">
<h3>Upgrade<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Before upgrading, make a backup of all data:</div>
<div class="line">- database (with <a class="reference external" href="https://www.postgresql.org/docs/11/app-pgdump.html">pg_dump</a> for instance)</div>
<div class="line">- upload directory (see <a class="reference external" href="installation.html#environment-variables">Environment variables</a>)</div>
</div>
</div>
<div class="section" id="id4">
<h4>Dev environment<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p>Stop the application and pull the repository:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ git pull
</pre></div>
</div>
<ul class="simple">
<li><p>Update <strong>.env</strong> if needed</p></li>
<li><p>Upgrade packages and database:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install-dev
$ make upgrade-db
</pre></div>
</div>
<ul class="simple">
<li><p>Restart the server:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make serve
</pre></div>
</div>
<ul class="simple">
<li><p>Run dramatiq workers:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run-workers
</pre></div>
</div>
</div>
<div class="section" id="prod-environment">
<h4>Prod environment<a class="headerlink" href="#prod-environment" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p>Stop the application and pull the repository:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ git pull
</pre></div>
</div>
<ul class="simple">
<li><p>Update <strong>Makefile.custom.config</strong> if needed</p></li>
<li><p>Upgrade packages and database:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make install
$ make upgrade-db
</pre></div>
</div>
<ul class="simple">
<li><p>Restart the server and dramatiq workers:</p></li>
</ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="deployment">
<h2>Deployment<a class="headerlink" href="#deployment" title="Permalink to this headline"></a></h2>
<p>There are several ways to start <strong>FitTrackee</strong> web application and task queue
library.
One way is to use a <strong>systemd</strong> services and <strong>Nginx</strong> to proxy pass to <strong>Gunicorn</strong>.</p>
<p>Examples (to update depending on your application configuration and given distribution):</p>
<ul class="simple">
<li><p>for application: <code class="docutils literal notranslate"><span class="pre">fittrackee.service</span></code></p></li>
</ul>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">Unit</span><span class="p">]</span>
<span class="n">Description</span><span class="o">=</span><span class="n">FitTrackee</span> <span class="n">service</span>
<span class="n">After</span><span class="o">=</span><span class="n">network</span><span class="o">.</span><span class="n">target</span>
<span class="n">After</span><span class="o">=</span><span class="n">postgresql</span><span class="o">.</span><span class="n">service</span>
<span class="n">After</span><span class="o">=</span><span class="n">redis</span><span class="o">.</span><span class="n">service</span>
<span class="n">StartLimitIntervalSec</span><span class="o">=</span><span class="mi">0</span>
<span class="p">[</span><span class="n">Service</span><span class="p">]</span>
<span class="n">Type</span><span class="o">=</span><span class="n">simple</span>
<span class="n">Restart</span><span class="o">=</span><span class="n">always</span>
<span class="n">RestartSec</span><span class="o">=</span><span class="mi">1</span>
<span class="n">User</span><span class="o">=&lt;</span><span class="n">USER</span><span class="o">&gt;</span>
<span class="n">StandardOutput</span><span class="o">=</span><span class="n">syslog</span>
<span class="n">StandardError</span><span class="o">=</span><span class="n">syslog</span>
<span class="n">SyslogIdentifier</span><span class="o">=</span><span class="n">fittrackee</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;APP_SECRET_KEY=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;APP_LOG=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;UPLOAD_FOLDER=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;DATABASE_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;UI_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;EMAIL_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;SENDER_EMAIL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;REDIS_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;TILE_SERVER_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;MAP_ATTRIBUTION=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;WEATHER_API_KEY=&quot;</span>
<span class="n">WorkingDirectory</span><span class="o">=/</span><span class="n">home</span><span class="o">/&lt;</span><span class="n">USER</span><span class="o">&gt;/&lt;</span><span class="n">FITTRACKEE</span> <span class="n">DIRECTORY</span><span class="o">&gt;</span>
<span class="n">ExecStart</span><span class="o">=/</span><span class="n">home</span><span class="o">/&lt;</span><span class="n">USER</span><span class="o">&gt;/&lt;</span><span class="n">FITTRACKEE</span> <span class="n">DIRECTORY</span><span class="o">&gt;/.</span><span class="n">venv</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">gunicorn</span> <span class="o">-</span><span class="n">b</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">5000</span> <span class="s2">&quot;fittrackee:create_app()&quot;</span> <span class="o">--</span><span class="n">error</span><span class="o">-</span><span class="n">logfile</span> <span class="o">/</span><span class="n">home</span><span class="o">/&lt;</span><span class="n">USER</span><span class="o">&gt;/&lt;</span><span class="n">FITTRACKEE</span> <span class="n">DIRECTORY</span><span class="o">&gt;/</span><span class="n">gunicorn</span><span class="o">.</span><span class="n">log</span>
<span class="n">Restart</span><span class="o">=</span><span class="n">always</span>
<span class="p">[</span><span class="n">Install</span><span class="p">]</span>
<span class="n">WantedBy</span><span class="o">=</span><span class="n">multi</span><span class="o">-</span><span class="n">user</span><span class="o">.</span><span class="n">target</span>
</pre></div>
</div>
<ul class="simple">
<li><p>for task queue workers: <code class="docutils literal notranslate"><span class="pre">fittrackee_workers.service</span></code></p></li>
</ul>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">Unit</span><span class="p">]</span>
<span class="n">Description</span><span class="o">=</span><span class="n">FitTrackee</span> <span class="n">task</span> <span class="n">queue</span> <span class="n">service</span>
<span class="n">After</span><span class="o">=</span><span class="n">network</span><span class="o">.</span><span class="n">target</span>
<span class="n">After</span><span class="o">=</span><span class="n">postgresql</span><span class="o">.</span><span class="n">service</span>
<span class="n">After</span><span class="o">=</span><span class="n">redis</span><span class="o">.</span><span class="n">service</span>
<span class="n">StartLimitIntervalSec</span><span class="o">=</span><span class="mi">0</span>
<span class="p">[</span><span class="n">Service</span><span class="p">]</span>
<span class="n">Type</span><span class="o">=</span><span class="n">simple</span>
<span class="n">Restart</span><span class="o">=</span><span class="n">always</span>
<span class="n">RestartSec</span><span class="o">=</span><span class="mi">1</span>
<span class="n">User</span><span class="o">=&lt;</span><span class="n">USER</span><span class="o">&gt;</span>
<span class="n">StandardOutput</span><span class="o">=</span><span class="n">syslog</span>
<span class="n">StandardError</span><span class="o">=</span><span class="n">syslog</span>
<span class="n">SyslogIdentifier</span><span class="o">=</span><span class="n">fittrackee_workers</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;FLASK_APP=fittrackee&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;APP_SECRET_KEY=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;APP_LOG=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;UPLOAD_FOLDER=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;DATABASE_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;UI_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;EMAIL_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;SENDER_EMAIL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;REDIS_URL=&quot;</span>
<span class="n">WorkingDirectory</span><span class="o">=/</span><span class="n">home</span><span class="o">/&lt;</span><span class="n">USER</span><span class="o">&gt;/&lt;</span><span class="n">FITTRACKEE</span> <span class="n">DIRECTORY</span><span class="o">&gt;</span>
<span class="n">ExecStart</span><span class="o">=/</span><span class="n">home</span><span class="o">/&lt;</span><span class="n">USER</span><span class="o">&gt;/&lt;</span><span class="n">FITTRACKEE</span> <span class="n">DIRECTORY</span><span class="o">&gt;/.</span><span class="n">venv</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">flask</span> <span class="n">worker</span> <span class="o">--</span><span class="n">processes</span> <span class="o">&lt;</span><span class="n">NUMBER</span> <span class="n">OF</span> <span class="n">PROCESSES</span><span class="o">&gt;</span>
<span class="n">Restart</span><span class="o">=</span><span class="n">always</span>
<span class="p">[</span><span class="n">Install</span><span class="p">]</span>
<span class="n">WantedBy</span><span class="o">=</span><span class="n">multi</span><span class="o">-</span><span class="n">user</span><span class="o">.</span><span class="n">target</span>
</pre></div>
</div>
<ul class="simple">
<li><p><strong>Nginx</strong> configuration:</p></li>
</ul>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>server {
listen 443 ssl;
server_name example.com;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
server {
listen 80;
server_name example.com;
location / {
return 301 https://example.com$request_uri;
}
}
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>More information on <a class="reference external" href="https://docs.gunicorn.org/en/stable/deploy.html">Gunicorn documentation</a></p>
</div>
</div>
</div> </div>

Binary file not shown.

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; FitTrackee 0.3.0-beta <title>Search &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -44,7 +44,8 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Administrator &#8212; FitTrackee 0.3.0-beta <title>Administrator &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Troubleshooting &#8212; FitTrackee 0.3.0-beta <title>Troubleshooting &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>User &#8212; FitTrackee 0.3.0-beta <title>User &#8212; FitTrackee 0.4.0
documentation</title> documentation</title>
<link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" /> <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@ -40,7 +40,8 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.3.0</b></span> <span class="navbar-text navbar-version pull-left"><b>0.4.0
</b></span>
</div> </div>
<div class="collapse navbar-collapse nav-collapse"> <div class="collapse navbar-collapse nav-collapse">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 KiB

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 KiB

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -54,18 +54,37 @@ body {
} }
.alert-danger { .alert-danger {
background-color: #dc6460; background-color: #f2dede;
border-color: transparent; border-color: #dca7a7;
color: #a94442;
} }
.alert-info { .alert-info {
background-color: #3eb3e3; background-color: #d9edf7;
border-color: transparent; border-color: #9acfea;
color: #31708f;
} }
.alert-warning { .alert-warning {
background-color: #f5894f; background-color: #fcf8e3;
border-color: transparent; border-color: #f5e79e;
color: #8a6d3b;
}
.descname {
border-top: solid 3px #a18bac;
border-radius: unset;
padding: 6px;
}
dl.field-list > dt {
background: #f0f0f0;
border-left: solid 3px #ccc;
color: #555;
}
.envvar {
margin-top: 30px;
} }
.footer { .footer {

View File

@ -1,7 +1,7 @@
Activities Activities
########## ##########
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
activities.get_activities, activities.get_activities,
activities.get_activity, activities.get_activity,

View File

@ -1,7 +1,7 @@
Authentication Authentication
############## ##############
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
auth.register_user, auth.register_user,
auth.login_user, auth.login_user,

View File

@ -1,7 +1,7 @@
Configuration Configuration
############# #############
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
config.get_application_config, config.get_application_config,
config.update_application_config, config.update_application_config,

View File

@ -1,6 +1,6 @@
Records Records
####### #######
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
records.get_records records.get_records

View File

@ -1,7 +1,7 @@
Sports Sports
###### ######
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
sports.get_sports, sports.get_sports,
sports.get_sport, sports.get_sport,

View File

@ -1,7 +1,7 @@
Statistics Statistics
########## ##########
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
stats.get_activities_by_time, stats.get_activities_by_time,
stats.get_activities_by_sport, stats.get_activities_by_sport,

View File

@ -1,7 +1,7 @@
Users Users
##### #####
.. autoflask:: fittrackee_api:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
users.get_users, users.get_users,
users.get_single_user, users.get_single_user,

View File

@ -16,7 +16,7 @@ from pathlib import Path
import sphinx_bootstrap_theme import sphinx_bootstrap_theme
sys.path.insert(0, os.path.abspath('../../fittrackee_api')) sys.path.insert(0, os.path.abspath('../../fittrackee'))
def setup(app): def setup(app):

View File

@ -4,13 +4,10 @@ Features
List List
~~~~ ~~~~
Account
^^^^^^^
- A user can create, update and deleted his account
- Password reset is now available
Administration Administration
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
(*new in 0.3.0*)
- **Application** - **Application**
The following parameters can be set: The following parameters can be set:
@ -30,6 +27,12 @@ Administration
- enable or disable a sport (a sport can be disabled even if activity with this sport exists) - enable or disable a sport (a sport can be disabled even if activity with this sport exists)
Account
^^^^^^^
- A user can create, update and deleted his account
- A user can reset his password (*new in 0.3.0*)
Activities/Workouts Activities/Workouts
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
- 6 sports supported: - 6 sports supported:

View File

@ -22,7 +22,7 @@ FitTrackee
Map <https://www.openstreetmap.org>`__. Map <https://www.openstreetmap.org>`__.
| It is also possible to add a workout without a gpx file. | It is also possible to add a workout without a gpx file.
| **Still under development (not ready for production).** | **Still under heavy development (some features may be unstable).**
| (see `issues <https://github.com/SamR1/FitTrackee/issues>`__ for more information) | (see `issues <https://github.com/SamR1/FitTrackee/issues>`__ for more information)
.. figure:: _images/fittrackee_screenshot-01.png .. figure:: _images/fittrackee_screenshot-01.png

View File

@ -22,194 +22,221 @@ Prerequisites
- PostgreSQL database (10+) - PostgreSQL database (10+)
- Redis for task queue - Redis for task queue
- Python 3.7+ - Python 3.7+
- `Poetry <https://poetry.eustace.io>`__ - `Poetry <https://poetry.eustace.io>`__ (for installation from sources only)
- `Yarn <https://yarnpkg.com>`__ and
`serve <https://github.com/zeit/serve>`__
- API key from `Dark Sky <https://darksky.net/dev>`__ [not mandatory] - API key from `Dark Sky <https://darksky.net/dev>`__ [not mandatory]
- SMTP provider - SMTP provider
- `Yarn <https://yarnpkg.com>`__ (for development only)
- Docker (for development only, to start `MailHog <https://github.com/mailhog/MailHog>`__)
.. note::
Installation | The following steps describe an installation on Linux systems (tested
~~~~~~~~~~~~
| The following steps describe an installation on Linux systems (tested
on Debian and Arch). on Debian and Arch).
| On other OS, some issues can be encountered and adaptations may be | On other OS, some issues can be encountered and adaptations may be
necessary. necessary.
.. warning::
Since FitTrackee 0.2.1, Python packages installation needs Poetry. To install it on ArchLinux:
.. code-block:: bash
$ yay poetry
$ poetry --version
Poetry 1.0.5
# optional
$ poetry config virtualenvs.in-project true
For other OS, see `Poetry Documentation <https://python-poetry.org/docs/#installation>`__
Dev environment
^^^^^^^^^^^^^^^
- Clone this repo:
.. code:: bash
$ git clone https://github.com/SamR1/FitTrackee.git
$ cd FitTrackee
- Update **Makefile.config** file if needed and copy/paste the
**ThunderForest** and **Dark Sky** API keys value in
**Makefile.custom.config** file (see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv, React and all related packages and
initialize the database:
.. code:: bash
$ make install-dev
$ make install-db
- Start the server and the client:
.. code:: bash
$ make serve
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Open http://localhost:3000 and login (the email is ``admin@example.com``
and the password ``mpwoadmin``) or register
Prod environment
^^^^^^^^^^^^^^^^
.. warning::
Note that FitTrackee is not production-ready yet
- Download the last release (for now, it is the beta release v0.3.0):
.. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.3.0-beta.tar.gz
$ tar -xzf v0.3.0-beta.tar.gz
$ mv FitTrackee-0.3.0-beta FitTrackee
$ cd FitTrackee
- Update **Makefile.config** file if needed and copy/paste the
**ThunderForest** and **Dark Sky** API keys value in
**Makefile.custom.config** file (see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv, React and all related packages and
initialize the database:
.. code:: bash
$ make install
$ make install-db
- Build the client:
.. code:: bash
$ make build-client
- Start the server and the client:
.. code:: bash
$ make run
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Open http://localhost:3000, log in as admin (the email is
``admin@example.com`` and the password ``mpwoadmin``) and change the
password
Upgrade
~~~~~~~
.. warning::
| Before upgrading, make a backup of all data:
| - database (with `pg_dump <https://www.postgresql.org/docs/11/app-pgdump.html>`__ for instance)
| - upload directory: **FitTrackee/fittrackee_api/fittrackee_api/uploads/**
Dev environment
^^^^^^^^^^^^^^^
- Stop the application and pull the repository:
.. code:: bash
$ git pull
- Update **Makefile.config** and **Makefile.custom.config** file if needed
- Upgrade packages and database:
.. code:: bash
$ make install-dev
$ make upgrade-db
- Restart the server and the client:
.. code:: bash
$ make serve
Prod environment
^^^^^^^^^^^^^^^^
``TODO``
Environment variables Environment variables
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
The following environment variables must be defined in **Makefile.custom.config**: .. warning::
| Since FitTrackee 0.4.0, ``Makefile.custom.config`` is replaced by ``.env``
.. cssclass:: table-bordered table-striped The following environment variables are used by **FitTrackee** web application
or the task processing library. They are not all mandatory depending on
deployment method.
===================================== ============================================== ==================================== .. envvar:: FLASK_APP
variable description app default value
===================================== ============================================== ==================================== | Name of the module to import at flask run.
``REACT_APP_API_URL`` Fittrackee API URL no default value, must be initialized | ``FLASK_APP`` should contain ``$(PWD)/fittrackee/__main__.py`` with installation from sources, else ``fittrackee``.
``REACT_APP_GPX_LIMIT_IMPORT`` max. number of gpx file in zip archive 10 (*deprecated in 0.3.0*)
``REACT_APP_MAX_SINGLE_FILE_SIZE`` max. size of a gpx or picture file 1MB (*deprecated in 0.3.0*)
``REACT_APP_MAX_ZIP_FILE_SIZE`` max. size of a zip archive 10MB (*deprecated in 0.3.0*) .. envvar:: HOST
``REACT_APP_ALLOW_REGISTRATION`` allows users to register true (*deprecated in 0.3.0*)
``REACT_APP_THUNDERFOREST_API_KEY`` ThunderForest API key (*deprecated in 0.x.x*, use ``TILE_SERVER_URL`` **and** ``MAP_ATTRIBUTION`` instead) **FitTrackee** host.
``TILE_SERVER_URL`` Tile server URL (with api key if needed) ``https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png``
``MAP_ATTRIBUTION`` Map attribution (if using another tile server) ``&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`` :default: 0.0.0.0
``UI_URL`` application URL no default value, must be initialized
``EMAIL_URL`` email URL with credentials no default value, must be initialized (see below)
``SENDER_EMAIL`` application sender email address no default value, must be initialized .. envvar:: PORT
``REDIS_URL`` Redis instance used by Dramatiq local Redis instance
``WORKERS_PROCESSES`` number of process used by Dramatiq no default value, must be initialized **FitTrackee** port.
===================================== ============================================== ====================================
:default: 5000
.. envvar:: APP_SETTINGS
**FitTrackee** configuration.
:default: fittrackee.config.ProductionConfig
.. envvar:: APP_SECRET_KEY
**FitTrackee** secret key, must be initialized in production environment.
.. envvar:: APP_WORKERS
Number of workers spawned by **Gunicorn**.
:default: 1
.. envvar:: APP_LOG 🆕
.. versionadded:: 0.4.0
Path to log file
.. envvar:: UPLOAD_FOLDER 🆕
.. versionadded:: 0.4.0
Directory containing uploaded files.
:default: `fittrackee/uploads/`
.. danger::
| With installation from PyPI, the directory will be located in
**virtualenv** directory if the variable is not initialized.
.. envvar:: DATABASE_URL
| Database URL with username and password, must be initialized in production environment.
| For example in dev environment : ``postgres://fittrackee:fittrackee@localhost:5432/fittrackee``
.. envvar:: DATABASE_DISABLE_POOLING 🆕
.. versionadded:: 0.4.0
Disable pooling if needed (when starting application with **FitTrackee** entry point and not directly with **Gunicorn**),
see `SqlAlchemy documentation <https://docs.sqlalchemy.org/en/13/core/pooling.html#using-connection-pools-with-multiprocessing-or-os-fork>`__.
:default: false
.. envvar:: UI_URL
**FitTrackee** URL, needed for links in emails.
.. envvar:: EMAIL_URL
.. versionadded:: 0.3.0
Email URL with credentials, see `Emails <installation.html#emails>`__.
.. envvar:: SENDER_EMAIL
.. versionadded:: 0.3.0
**FitTrackee** sender email address.
.. envvar:: REDIS_URL
.. versionadded:: 0.3.0
Redis instance used by **Dramatiq**.
:default: local Redis instance (``redis://``)
.. envvar:: WORKERS_PROCESSES
.. versionadded:: 0.3.0
Number of processes used by **Dramatiq**.
.. envvar:: TILE_SERVER_URL 🆕
.. versionadded:: 0.4.0
Tile server URL (with api key if needed), see `Map tile server <installation.html#map-tile-server>`__.
:default: `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`
.. envvar:: MAP_ATTRIBUTION 🆕
.. versionadded:: 0.4.0
Map attribution (if using another tile server), see `Map tile server <installation.html#map-tile-server>`__.
:default: `&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`
.. envvar:: WEATHER_API_KEY
.. versionchanged:: 0.4.0 ⚠️ replaces ``WEATHER_API``
**Dark Sky** API key for weather data (not mandatory).
.. envvar:: REACT_APP_API_URL
**FitTrackee** API URL, only needed in dev environment.
Deprecated variables
^^^^^^^^^^^^^^^^^^^^
.. envvar:: REACT_APP_GPX_LIMIT_IMPORT
.. deprecated:: 0.3.0 now stored in database
Maximum number of gpx file in zip archive.
:default: 10
.. envvar:: REACT_APP_MAX_SINGLE_FILE_SIZE
.. deprecated:: 0.3.0 now stored in database
Maximum size of a gpx or picture file.
:default: 1MB
.. envvar:: REACT_APP_MAX_ZIP_FILE_SIZE
.. deprecated:: 0.3.0 now stored in database
Maximum size of a zip archive.
:default: 10MB
.. envvar:: REACT_APP_ALLOW_REGISTRATION
.. deprecated:: 0.3.0 now stored in database
Allows users to register.
:default: true
.. envvar:: REACT_APP_THUNDERFOREST_API_KEY
.. deprecated:: 0.4.0 see `TILE_SERVER_URL <installation.html#envvar-TILE_SERVER_URL>`__
ThunderForest API key.
.. warning:: .. warning::
Since FitTrackee 0.3.0, some applications parameters are now stored in database. | Since FitTrackee 0.3.0, some applications parameters are now stored in database.
Related environment variables are needed to initialize database. | Related environment variables are needed to initialize database when upgrading from version prior 0.3.0.
Emails Emails
^^^^^^ ^^^^^^
*new in 0.3.0* .. versionadded:: 0.3.0
To send emails, a valid ``EMAIL_URL`` must be provided: To send emails, a valid ``EMAIL_URL`` must be provided:
@ -220,15 +247,392 @@ To send emails, a valid ``EMAIL_URL`` must be provided:
Map tile server Map tile server
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
*new in 0.x.x* .. versionadded:: 0.4.0
Default tile server is now **OpenStreetMap**'s standard tile layer (if environment variables are not initialized). Default tile server is now **OpenStreetMap**'s standard tile layer (if environment variables are not initialized).
The tile server can be changed by updating ``TILE_SERVER_URL`` and ``MAP_ATTRIBUTION`` variables (`list of tile servers <https://wiki.openstreetmap.org/wiki/Tile_servers>`__). The tile server can be changed by updating ``TILE_SERVER_URL`` and ``MAP_ATTRIBUTION`` variables (`list of tile servers <https://wiki.openstreetmap.org/wiki/Tile_servers>`__).
To keep using ThunderForest Outdoors, the configuration is: To keep using **ThunderForest Outdoors**, the configuration is:
- ``TILE_SERVER_URL=https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=XXXX`` where **XXXX** is ThunderForest API key - ``TILE_SERVER_URL=https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=XXXX`` where **XXXX** is **ThunderForest** API key
- ``MAP_ATTRIBUTION=&copy; <a href="http://www.thunderforest.com/">Thunderforest</a>, &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`` - ``MAP_ATTRIBUTION=&copy; <a href="http://www.thunderforest.com/">Thunderforest</a>, &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors``
.. note:: .. note::
Check the terms of service of tile provider for map attribution | Check the terms of service of tile provider for map attribution
From PyPI
~~~~~~~~~
.. note::
| Recommended way on production.
.. warning::
| Note that FitTrackee is under heavy development, some features may be unstable.
Installation
^^^^^^^^^^^^
- Create and activate a virtualenv
- Install **FitTrackee** with pip
.. code-block:: bash
$ pip install fittrackee
- Create ``fittrackee`` database
Example :
.. code-block:: sql
CREATE DATABASE fittrackee;
CREATE USER fittrackee WITH PASSWORD '<PASSWORD>';
GRANT ALL PRIVILEGES ON DATABASE fittrackee TO fittrackee;
- Initialize environment variables, see `Environment variables <installation.html#environment-variables>`__
For instance, copy and update ``.env`` file from ``.env.example`` and source the file.
.. code-block:: bash
$ nano .env
$ source .env
- Upgrade database schema
.. code-block:: bash
$ fittrackee_upgrade_db
- Initialize database
.. code-block:: bash
$ fittrackee_init_data
- Start the application
.. code-block:: bash
$ fittrackee
- Start task queue workers
.. code-block:: bash
$ fittrackee_worker --processes 2
.. note::
| To start application and workers with **systemd** service, see `Deployment <installation.html#deployment>`__
Upgrade
^^^^^^^
.. warning::
| Before upgrading, make a backup of all data:
| - database (with `pg_dump <https://www.postgresql.org/docs/11/app-pgdump.html>`__ for instance)
| - upload directory (see `Environment variables <installation.html#environment-variables>`__)
- Activate the virtualenv
- Upgrade with pip
.. code-block:: bash
$ pip install -U fittrackee
- Update environment variables if needed and source environment variables file
.. code-block:: bash
$ nano .env
$ source .env
- Upgrade database if needed
.. code-block:: bash
$ fittrackee_upgrade_db
- Restart the application and task queue workers.
From sources
~~~~~~~~~~~~~
.. warning::
| Since FitTrackee 0.2.1, Python packages installation needs Poetry.
| To install it on ArchLinux:
.. code-block:: bash
$ yay poetry
$ poetry --version
Poetry 1.0.10
# optional
$ poetry config virtualenvs.in-project true
For other OS, see `Poetry Documentation <https://python-poetry.org/docs/#installation>`__
Installation
^^^^^^^^^^^^
Dev environment
"""""""""""""""
- Clone this repo:
.. code:: bash
$ git clone https://github.com/SamR1/FitTrackee.git
$ cd FitTrackee
- Create **Makefile.custom.config** from example and update it
(see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv, React and all related packages and
initialize the database:
.. code:: bash
$ make install-dev
$ make install-db
- Start the server and the client:
.. code:: bash
$ make serve
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Open http://localhost:3000 and log in (the email is ``admin@example.com``
and the password ``mpwoadmin``) or register
Production environment
""""""""""""""""""""""
.. warning::
| Note that FitTrackee is under heavy development, some features may be unstable.
- Download the last release (for now, it is the release v0.4.0):
.. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.4.0.tar.gz
$ tar -xzf v0.4.0.tar.gz
$ mv FitTrackee-0.4.0 FitTrackee
$ cd FitTrackee
- Create **Makefile.custom.config** from example and update it
(see `Environment variables <installation.html#environment-variables>`__).
- Install Python virtualenv and all related packages:
.. code:: bash
$ make install-python
- Initialize the database (**after updating** ``db/create.sql`` **to change
database credentials**):
.. code:: bash
$ make install-db
- Start the server and dramatiq workers:
.. code:: bash
$ make run
Open http://localhost:5000, log in as admin (the email is
``admin@example.com`` and the password ``mpwoadmin``) and change the
password
Upgrade
^^^^^^^
.. warning::
| Before upgrading, make a backup of all data:
| - database (with `pg_dump <https://www.postgresql.org/docs/11/app-pgdump.html>`__ for instance)
| - upload directory (see `Environment variables <installation.html#environment-variables>`__)
Dev environment
"""""""""""""""
- Stop the application and pull the repository:
.. code:: bash
$ git pull
- Update **.env** if needed
- Upgrade packages and database:
.. code:: bash
$ make install-dev
$ make upgrade-db
- Restart the server:
.. code:: bash
$ make serve
- Run dramatiq workers:
.. code:: bash
$ make run-workers
Prod environment
""""""""""""""""
- Stop the application and pull the repository:
.. code:: bash
$ git pull
- Update **Makefile.custom.config** if needed
- Upgrade packages and database:
.. code:: bash
$ make install
$ make upgrade-db
- Restart the server and dramatiq workers:
.. code:: bash
$ make run
Deployment
~~~~~~~~~~~~~
There are several ways to start **FitTrackee** web application and task queue
library.
One way is to use a **systemd** services and **Nginx** to proxy pass to **Gunicorn**.
Examples (to update depending on your application configuration and given distribution):
- for application: ``fittrackee.service``
.. code-block::
[Unit]
Description=FitTrackee service
After=network.target
After=postgresql.service
After=redis.service
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=<USER>
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=fittrackee
Environment="APP_SECRET_KEY="
Environment="APP_LOG="
Environment="UPLOAD_FOLDER="
Environment="DATABASE_URL="
Environment="UI_URL="
Environment="EMAIL_URL="
Environment="SENDER_EMAIL="
Environment="REDIS_URL="
Environment="TILE_SERVER_URL="
Environment="MAP_ATTRIBUTION="
Environment="WEATHER_API_KEY="
WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY>
ExecStart=/home/<USER>/<FITTRACKEE DIRECTORY>/.venv/bin/gunicorn -b 127.0.0.1:5000 "fittrackee:create_app()" --error-logfile /home/<USER>/<FITTRACKEE DIRECTORY>/gunicorn.log
Restart=always
[Install]
WantedBy=multi-user.target
- for task queue workers: ``fittrackee_workers.service``
.. code-block::
[Unit]
Description=FitTrackee task queue service
After=network.target
After=postgresql.service
After=redis.service
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=<USER>
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=fittrackee_workers
Environment="FLASK_APP=fittrackee"
Environment="APP_SECRET_KEY="
Environment="APP_LOG="
Environment="UPLOAD_FOLDER="
Environment="DATABASE_URL="
Environment="UI_URL="
Environment="EMAIL_URL="
Environment="SENDER_EMAIL="
Environment="REDIS_URL="
WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY>
ExecStart=/home/<USER>/<FITTRACKEE DIRECTORY>/.venv/bin/flask worker --processes <NUMBER OF PROCESSES>
Restart=always
[Install]
WantedBy=multi-user.target
- **Nginx** configuration:
.. code-block::
server {
listen 443 ssl;
server_name example.com;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
server {
listen 80;
server_name example.com;
location / {
return 301 https://example.com$request_uri;
}
}
.. note::
More information on `Gunicorn documentation <https://docs.gunicorn.org/en/stable/deploy.html>`__

38
e2e/test_activities.py Normal file
View File

@ -0,0 +1,38 @@
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select, WebDriverWait
from .utils import TEST_URL, register_valid_user
class TestActivity:
def test_user_can_add_activity_without_gpx(self, selenium):
register_valid_user(selenium)
nav_items = selenium.find_elements_by_class_name('nav-item')
nav_items[3].click()
selenium.implicitly_wait(1)
radio_buttons = selenium.find_elements_by_class_name(
'add-activity-radio'
)
radio_buttons[1].click()
selenium.find_element_by_name('title').send_keys('Activity title')
select = Select(selenium.find_element_by_name('sport_id'))
select.select_by_index(1)
selenium.find_element_by_name('activity_date').send_keys('2018-12-20')
selenium.find_element_by_name('activity_time').send_keys('14:05')
selenium.find_element_by_name('duration').send_keys('01:00:00')
selenium.find_element_by_name('distance').send_keys('10')
selenium.find_element_by_class_name('btn-primary').click()
WebDriverWait(selenium, 10).until(
EC.url_changes(f"{TEST_URL}/activities/add")
)
activity_details = selenium.find_element_by_class_name(
'activity-details'
).text
assert 'Duration: 1:00:00' in activity_details
assert 'Distance: 10 km' in activity_details
assert 'Average speed: 10 km/h' in activity_details
assert 'Max. speed: 10 km/h' in activity_details

17
e2e/test_index.py Normal file
View File

@ -0,0 +1,17 @@
from .utils import TEST_URL
class TestIndex:
def test_title_contains_fittrackee(self, selenium):
selenium.get(TEST_URL)
assert 'FitTrackee' in selenium.title
def test_navbar_contains_all_links(self, selenium):
selenium.get(TEST_URL)
nav = selenium.find_element_by_tag_name('nav').text
assert "FitTrackee" in nav
assert "Dashboard" in nav
assert "Login" in nav
assert "Register" in nav
assert "en" in nav

40
e2e/test_login.py Normal file
View File

@ -0,0 +1,40 @@
from .utils import TEST_URL, assert_navbar, login_valid_user
URL = f'{TEST_URL}/login'
class TestLogin:
def test_navbar_contains_login(self, selenium):
selenium.get(URL)
nav = selenium.find_element_by_tag_name('nav').text
assert 'Login' in nav
def test_h1_contains_login(self, selenium):
selenium.get(URL)
title = selenium.find_element_by_tag_name('h1').text
assert 'Login' in title
def test_it_displays_login_form(self, selenium):
selenium.get(URL)
inputs = selenium.find_elements_by_tag_name('input')
assert len(inputs) == 3
assert inputs[0].get_attribute('name') == 'email'
assert inputs[0].get_attribute('type') == 'email'
assert inputs[1].get_attribute('name') == 'password'
assert inputs[1].get_attribute('type') == 'password'
assert inputs[2].get_attribute('name') == ''
assert inputs[2].get_attribute('type') == 'submit'
def test_user_can_log_in(self, selenium):
user = {
'username': 'admin',
'email': 'admin@example.com',
'password': 'mpwoadmin',
}
login_valid_user(selenium, user)
assert_navbar(selenium, user)

19
e2e/test_logout.py Normal file
View File

@ -0,0 +1,19 @@
from .utils import register_valid_user
class TestLogout:
def test_user_can_log_out(self, selenium):
user = register_valid_user(selenium)
nav_items = selenium.find_elements_by_class_name('nav-item')
nav_items[5].click()
selenium.implicitly_wait(1)
nav = selenium.find_element_by_tag_name('nav').text
assert 'Register' in nav
assert 'Login' in nav
assert user['username'] not in nav
assert 'Logout' not in nav
message = selenium.find_element_by_class_name('card-body').text
assert 'You are now logged out. Click here to log back in.' in message

20
e2e/test_profile.py Normal file
View File

@ -0,0 +1,20 @@
from .utils import TEST_URL, register_valid_user
URL = f'{TEST_URL}/profile'
class TestProfile:
def test_it_displays_user_profile(self, selenium):
user = register_valid_user(selenium)
selenium.get(URL)
assert 'Profile' in selenium.find_element_by_tag_name('h1').text
assert (
user['username']
in selenium.find_element_by_class_name('userName').text
)
assert (
user['username']
in selenium.find_element_by_class_name('userName').text
)

141
e2e/test_registration.py Normal file
View File

@ -0,0 +1,141 @@
from .utils import (
TEST_URL,
assert_navbar,
random_string,
register,
register_valid_user,
)
URL = f'{TEST_URL}/register'
class TestRegistration:
def test_it_displays_registration_form(self, selenium):
selenium.get(URL)
selenium.implicitly_wait(1)
inputs = selenium.find_elements_by_tag_name('input')
assert len(inputs) == 5
assert inputs[0].get_attribute('name') == 'username'
assert inputs[0].get_attribute('type') == 'text'
assert inputs[1].get_attribute('name') == 'email'
assert inputs[1].get_attribute('type') == 'email'
assert inputs[2].get_attribute('name') == 'password'
assert inputs[2].get_attribute('type') == 'password'
assert inputs[3].get_attribute('name') == 'password_conf'
assert inputs[3].get_attribute('type') == 'password'
assert inputs[4].get_attribute('name') == ''
assert inputs[4].get_attribute('type') == 'submit'
def test_user_can_register(self, selenium):
user = register_valid_user(selenium)
assert_navbar(selenium, user)
def test_user_can_not_register_with_invalid_email(self, selenium):
user_name = random_string()
user_infos = {
'username': user_name,
'email': user_name,
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user_infos)
assert selenium.current_url == URL
nav = selenium.find_element_by_tag_name('nav').text
assert 'Register' in nav
assert 'Login' in nav
def test_user_can_not_register_if_username_is_already_taken(
self, selenium
):
user_name = random_string()
user_infos = {
'username': 'admin',
'email': f'{user_name}@example.com',
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user_infos)
assert selenium.current_url == URL
errors = selenium.find_element_by_tag_name('code').text
assert 'Sorry. That user already exists.' in errors
def test_user_can_not_register_if_email_is_already_taken(self, selenium):
user_name = random_string()
user_infos = {
'username': user_name,
'email': 'admin@example.com',
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user_infos)
assert selenium.current_url == URL
errors = selenium.find_element_by_tag_name('code').text
assert 'Sorry. That user already exists.' in errors
def test_user_can_not_register_if_username_is_too_short(self, selenium):
user_name = random_string(2)
user_infos = {
'username': user_name,
'email': 'admin@example.com',
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user_infos)
assert selenium.current_url == URL
errors = selenium.find_element_by_tag_name('code').text
assert '3 to 12 characters required for username.' in errors
def test_user_can_not_register_if_username_is_too_long(self, selenium):
user_name = random_string(13)
user_infos = {
'username': user_name,
'email': 'admin@example.com',
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user_infos)
assert selenium.current_url == URL
errors = selenium.find_element_by_tag_name('code').text
assert '3 to 12 characters required for username.' in errors
def test_it_displays_error_if_passwords_do_not_match(self, selenium):
user_name = random_string()
user_infos = {
'username': user_name,
'email': f'{user_name}@example.com',
'password': 'p@ssw0rd',
'password_conf': 'password',
}
register(selenium, user_infos)
assert selenium.current_url == URL
errors = selenium.find_element_by_tag_name('code').text
assert 'Password and password confirmation don\'t match' in errors
def test_it_displays_error_if_password_is_too_short(self, selenium):
user_name = random_string()
user_infos = {
'username': user_name,
'email': f'{user_name}@example.com',
'password': 'p@ss',
'password_conf': 'p@ss',
}
register(selenium, user_infos)
assert selenium.current_url == URL
errors = selenium.find_element_by_tag_name('code').text
assert '8 characters required for password.' in errors

73
e2e/utils.py Normal file
View File

@ -0,0 +1,73 @@
import os
import random
import string
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
TEST_APP_URL = os.getenv('TEST_APP_URL')
TEST_CLIENT_URL = os.getenv('TEST_CLIENT_URL')
E2E_ARGS = os.getenv('E2E_ARGS')
TEST_URL = TEST_CLIENT_URL if E2E_ARGS == 'client' else TEST_APP_URL
def random_string(length=8):
return ''.join(random.choice(string.ascii_letters) for x in range(length))
def register(selenium, user):
selenium.get(f'{TEST_URL}/register')
selenium.implicitly_wait(1)
username = selenium.find_element_by_name('username')
username.send_keys(user.get('username'))
email = selenium.find_element_by_name('email')
email.send_keys(user.get('email'))
password = selenium.find_element_by_name('password')
password.send_keys(user.get('password'))
password_conf = selenium.find_element_by_name('password_conf')
password_conf.send_keys(user.get('password_conf'))
submit_button = selenium.find_element_by_class_name('btn')
submit_button.click()
def login(selenium, user):
selenium.get(f'{TEST_URL}/login')
selenium.implicitly_wait(1)
email = selenium.find_element_by_name('email')
email.send_keys(user.get('email'))
password = selenium.find_element_by_name('password')
password.send_keys(user.get('password'))
submit_button = selenium.find_element_by_class_name('btn')
submit_button.click()
def register_valid_user(selenium):
user_name = random_string()
user = {
'username': user_name,
'email': f'{user_name}@example.com',
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user)
WebDriverWait(selenium, 10).until(EC.url_changes(f"{TEST_URL}/register"))
return user
def login_valid_user(selenium, user):
login(selenium, user)
WebDriverWait(selenium, 10).until(EC.url_changes(f"{TEST_URL}/login"))
return user
def assert_navbar(selenium, user):
nav = selenium.find_element_by_tag_name('nav').text
assert 'Register' not in nav
assert 'Login' not in nav
assert 'Dashboard' in nav
assert 'Workouts' in nav
assert 'Statistics' in nav
assert 'Add workout' in nav
assert user['username'] in nav
assert 'Logout' in nav
assert 'en' in nav

View File

@ -2,7 +2,7 @@ import logging
import os import os
from importlib import import_module, reload from importlib import import_module, reload
from flask import Flask from flask import Flask, render_template, send_file
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
from flask_dramatiq import Dramatiq from flask_dramatiq import Dramatiq
from flask_migrate import Migrate from flask_migrate import Migrate
@ -15,19 +15,27 @@ bcrypt = Bcrypt()
migrate = Migrate() migrate = Migrate()
email_service = Email() email_service = Email()
dramatiq = Dramatiq() dramatiq = Dramatiq()
appLog = logging.getLogger('fittrackee_api') log_file = os.getenv('APP_LOG')
logging.basicConfig(
filename=log_file,
format='%(asctime)s - %(name)s - %(levelname)s - ' '%(message)s',
datefmt='%Y/%m/%d %H:%M:%S',
)
appLog = logging.getLogger('fittrackee')
def create_app(): def create_app():
# instantiate the app # instantiate the app
app = Flask(__name__) app = Flask(__name__, static_folder='dist/static', template_folder='dist')
# set config # set config
with app.app_context(): with app.app_context():
app_settings = os.getenv('APP_SETTINGS') app_settings = os.getenv(
if app_settings == 'fittrackee_api.config.TestingConfig': 'APP_SETTINGS', 'fittrackee.config.ProductionConfig'
)
if app_settings == 'fittrackee.config.TestingConfig':
# reload config on tests # reload config on tests
config = import_module('fittrackee_api.config') config = import_module('fittrackee.config')
reload(config) reload(config)
app.config.from_object(app_settings) app.config.from_object(app_settings)
@ -91,4 +99,17 @@ def create_app():
) )
return response return response
@app.route('/favicon.ico')
def favicon():
return send_file(os.path.join(app.root_path, 'dist/favicon.ico'))
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
# workaround to serve images (not in static directory)
if path.startswith('img/'):
return send_file(os.path.join(app.root_path, 'dist', path))
else:
return render_template('index.html')
return app return app

103
fittrackee/__main__.py Normal file
View File

@ -0,0 +1,103 @@
# source for StandaloneApplication class:
# http://docs.gunicorn.org/en/stable/custom.html
import os
import shutil
import gunicorn.app.base
from fittrackee import create_app, db
from fittrackee.activities.models import Activity
from fittrackee.activities.utils import update_activity
from fittrackee.application.utils import init_config
from fittrackee.database_utils import init_database
from flask_dramatiq import worker
from flask_migrate import upgrade
from tqdm import tqdm
HOST = os.getenv('HOST', '0.0.0.0')
PORT = os.getenv('PORT', '5000')
WORKERS = os.getenv('APP_WORKERS', 1)
BASEDIR = os.path.abspath(os.path.dirname(__file__))
app = create_app()
dramatiq_worker = worker
class StandaloneApplication(gunicorn.app.base.BaseApplication):
def __init__(self, current_app, options=None):
self.options = options or {}
self.application = current_app
super().__init__()
def load_config(self):
config = {
key: value
for key, value in self.options.items()
if key in self.cfg.settings and value is not None
}
for key, value in config.items():
self.cfg.set(key.lower(), value)
def load(self):
return self.application
def upgrade_db():
with app.app_context():
upgrade(directory=BASEDIR + '/migrations')
@app.cli.command('drop-db')
def drop_db():
"""Empty database for dev environments."""
db.engine.execute("DROP TABLE IF EXISTS alembic_version;")
db.drop_all()
db.session.commit()
print('Database dropped.')
shutil.rmtree(app.config['UPLOAD_FOLDER'], ignore_errors=True)
print('Uploaded files deleted.')
@app.cli.command('init-data')
def init_data():
"""Init the database and application config."""
init_database(app)
@app.cli.command()
def recalculate():
print("Starting activities data refresh")
activities = (
Activity.query.filter(Activity.gpx != None) # noqa
.order_by(Activity.activity_date.asc()) # noqa
.all()
)
if len(activities) == 0:
print('➡️ no activities to upgrade.')
return None
pbar = tqdm(activities)
for activity in pbar:
update_activity(activity)
pbar.set_postfix(activitiy_id=activity.id)
db.session.commit()
@app.cli.command('init-app-config')
def init_app_config():
"""Init application configuration."""
print("Init application configuration")
config_created, _ = init_config()
if config_created:
print("Creation done!")
else:
print(
"Application configuration already existing in database. "
"Please use web application to update it."
)
def main():
options = {'bind': f'{HOST}:{PORT}', 'workers': WORKERS}
StandaloneApplication(app, options).run()
if __name__ == '__main__':
app.run()

View File

@ -4,7 +4,7 @@ import shutil
from datetime import datetime, timedelta from datetime import datetime, timedelta
import requests import requests
from fittrackee_api import appLog, db from fittrackee import appLog, db
from flask import Blueprint, Response, current_app, jsonify, request, send_file from flask import Blueprint, Response, current_app, jsonify, request, send_file
from sqlalchemy import exc from sqlalchemy import exc

View File

@ -1,7 +1,7 @@
import datetime import datetime
import os import os
from fittrackee_api import db from fittrackee import db
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from sqlalchemy.event import listens_for from sqlalchemy.event import listens_for
from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.ext.hybrid import hybrid_property

View File

@ -1,4 +1,4 @@
from fittrackee_api import appLog, db from fittrackee import appLog, db
from flask import Blueprint, jsonify, request from flask import Blueprint, jsonify, request
from sqlalchemy import exc from sqlalchemy import exc

View File

@ -1,6 +1,6 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from fittrackee_api import appLog, db from fittrackee import appLog, db
from flask import Blueprint, jsonify, request from flask import Blueprint, jsonify, request
from sqlalchemy import func from sqlalchemy import func

View File

@ -6,7 +6,7 @@ from datetime import datetime, timedelta
import gpxpy.gpx import gpxpy.gpx
import pytz import pytz
from fittrackee_api import appLog, db from fittrackee import appLog, db
from flask import current_app from flask import current_app
from sqlalchemy import exc from sqlalchemy import exc
from staticmap import Line, StaticMap from staticmap import Line, StaticMap

View File

@ -2,9 +2,9 @@ import os
import forecastio import forecastio
import pytz import pytz
from fittrackee_api import appLog from fittrackee import appLog
API_KEY = os.getenv('WEATHER_API') API_KEY = os.getenv('WEATHER_API_KEY')
def get_weather(point): def get_weather(point):

View File

@ -1,4 +1,4 @@
from fittrackee_api import appLog, db from fittrackee import appLog, db
from flask import Blueprint, current_app, jsonify, request from flask import Blueprint, current_app, jsonify, request
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
@ -34,7 +34,8 @@ def get_application_config():
"is_registration_enabled": false, "is_registration_enabled": false,
"max_single_file_size": 1048576, "max_single_file_size": 1048576,
"max_zip_file_size": 10485760, "max_zip_file_size": 10485760,
"max_users": 0 "max_users": 0,
"map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
}, },
"status": "success" "status": "success"
} }

View File

@ -1,4 +1,4 @@
from fittrackee_api import db from fittrackee import db
from flask import current_app from flask import current_app
from sqlalchemy.event import listens_for from sqlalchemy.event import listens_for

View File

@ -1,7 +1,7 @@
import os import os
from fittrackee_api import db from fittrackee import db
from fittrackee_api.users.models import User from fittrackee.users.models import User
from .models import AppConfig from .models import AppConfig

View File

@ -3,8 +3,9 @@ import os
from dramatiq.brokers.redis import RedisBroker from dramatiq.brokers.redis import RedisBroker
from dramatiq.brokers.stub import StubBroker from dramatiq.brokers.stub import StubBroker
from flask import current_app from flask import current_app
from sqlalchemy.pool import NullPool
if os.getenv('APP_SETTINGS') == 'fittrackee_api.config.TestingConfig': if os.getenv('APP_SETTINGS') == 'fittrackee.config.TestingConfig':
broker = StubBroker broker = StubBroker
else: else:
broker = RedisBroker broker = RedisBroker
@ -20,7 +21,9 @@ class BaseConfig:
TOKEN_EXPIRATION_DAYS = 30 TOKEN_EXPIRATION_DAYS = 30
TOKEN_EXPIRATION_SECONDS = 0 TOKEN_EXPIRATION_SECONDS = 0
PASSWORD_TOKEN_EXPIRATION_SECONDS = 3600 PASSWORD_TOKEN_EXPIRATION_SECONDS = 3600
UPLOAD_FOLDER = os.path.join(current_app.root_path, 'uploads') UPLOAD_FOLDER = os.path.join(
os.getenv('UPLOAD_FOLDER', current_app.root_path), 'uploads'
)
PICTURE_ALLOWED_EXTENSIONS = {'jpg', 'png', 'gif'} PICTURE_ALLOWED_EXTENSIONS = {'jpg', 'png', 'gif'}
ACTIVITY_ALLOWED_EXTENSIONS = {'gpx', 'zip'} ACTIVITY_ALLOWED_EXTENSIONS = {'gpx', 'zip'}
TEMPLATES_FOLDER = os.path.join(current_app.root_path, 'email/templates') TEMPLATES_FOLDER = os.path.join(current_app.root_path, 'email/templates')
@ -68,3 +71,18 @@ class TestingConfig(BaseConfig):
TOKEN_EXPIRATION_SECONDS = 3 TOKEN_EXPIRATION_SECONDS = 3
PASSWORD_TOKEN_EXPIRATION_SECONDS = 3 PASSWORD_TOKEN_EXPIRATION_SECONDS = 3
UPLOAD_FOLDER = '/tmp/fitTrackee/uploads' UPLOAD_FOLDER = '/tmp/fitTrackee/uploads'
class ProductionConfig(BaseConfig):
"""Production configuration"""
DEBUG = False
# https://docs.sqlalchemy.org/en/13/core/pooling.html#using-connection-pools-with-multiprocessing-or-os-fork # noqa
SQLALCHEMY_ENGINE_OPTIONS = (
{'poolclass': NullPool}
if os.getenv('DATABASE_DISABLE_POOLING', False)
else {}
)
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SECRET_KEY = os.getenv('APP_SECRET_KEY')
DRAMATIQ_BROKER_URL = os.getenv('REDIS_URL', 'redis://')

View File

@ -0,0 +1,46 @@
from fittrackee import db
from fittrackee.activities.models import Sport
from fittrackee.application.utils import (
init_config,
update_app_config_from_database,
)
from fittrackee.users.models import User
def init_database(app):
"""Init the database."""
admin = User(
username='admin', email='admin@example.com', password='mpwoadmin'
)
admin.admin = True
admin.timezone = 'Europe/Paris'
db.session.add(admin)
sport = Sport(label='Cycling (Sport)')
sport.img = '/img/sports/cycling-sport.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Cycling (Transport)')
sport.img = '/img/sports/cycling-transport.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Hiking')
sport.img = '/img/sports/hiking.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Mountain Biking')
sport.img = '/img/sports/mountain-biking.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Running')
sport.img = '/img/sports/running.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Walking')
sport.img = '/img/sports/walking.png'
sport.is_default = True
db.session.add(sport)
db.session.commit()
_, db_app_config = init_config()
update_app_config_from_database(app, db_app_config)
print('Initial data stored in database.')

26
fittrackee/dist/asset-manifest.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"files": {
"main.css": "/static/css/main.9eb63bc2.chunk.css",
"main.js": "/static/js/main.474f2b2e.chunk.js",
"main.js.map": "/static/js/main.474f2b2e.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.2d7c76f9.js",
"runtime-main.js.map": "/static/js/runtime-main.2d7c76f9.js.map",
"static/js/2.8ad7236a.chunk.js": "/static/js/2.8ad7236a.chunk.js",
"static/js/2.8ad7236a.chunk.js.map": "/static/js/2.8ad7236a.chunk.js.map",
"index.html": "/index.html",
"precache-manifest.da13c9560c293f42e6b23c2cfaa288b6.js": "/precache-manifest.da13c9560c293f42e6b23c2cfaa288b6.js",
"service-worker.js": "/service-worker.js",
"static/css/main.9eb63bc2.chunk.css.map": "/static/css/main.9eb63bc2.chunk.css.map",
"static/js/2.8ad7236a.chunk.js.LICENSE.txt": "/static/js/2.8ad7236a.chunk.js.LICENSE.txt",
"static/media/en.501888db.svg": "/static/media/en.501888db.svg",
"static/media/fr.b75cd962.svg": "/static/media/fr.b75cd962.svg",
"static/media/mail-send.66b8d739.svg": "/static/media/mail-send.66b8d739.svg",
"static/media/password.488f5f4c.svg": "/static/media/password.488f5f4c.svg"
},
"entrypoints": [
"static/js/runtime-main.2d7c76f9.js",
"static/js/2.8ad7236a.chunk.js",
"static/css/main.9eb63bc2.chunk.css",
"static/js/main.474f2b2e.chunk.js"
]
}

BIN
fittrackee/dist/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Some files were not shown because too many files have changed in this diff Show More