Merged with dev and fixed conflicts

This commit is contained in:
Fmstrat 2022-07-18 09:16:17 -04:00
commit fc3eb2cc36
349 changed files with 17812 additions and 7523 deletions

View File

@ -25,6 +25,7 @@ export SENDER_EMAIL=
# Workouts # Workouts
# export TILE_SERVER_URL= # export TILE_SERVER_URL=
# export STATICMAP_SUBDOMAINS=
# export MAP_ATTRIBUTION= # export MAP_ATTRIBUTION=
# export DEFAULT_STATICMAP=False # export DEFAULT_STATICMAP=False
# export WEATHER_API_KEY= # export WEATHER_API_KEY=

34
.github/workflows/.tests-javascript.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Javascript CI
on:
push:
paths: ['fittrackee_client/**']
pull_request:
paths: ['fittrackee_client/**']
env:
working-directory: fittrackee_client
jobs:
javascript:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 17.x
uses: actions/setup-node@v2
with:
node-version: "17.x"
- name: Install yarn and dependencies
working-directory: ${{env.working-directory}}
run: |
npm install --global yarn
yarn install
- name: Lint
working-directory: ${{env.working-directory}}
run: yarn lint
- name: Tests
working-directory: ${{env.working-directory}}
run: yarn test:unit
- name: Build
working-directory: ${{env.working-directory}}
run: yarn build

98
.github/workflows/.tests-python.yml vendored Normal file
View File

@ -0,0 +1,98 @@
name: Python CI
on:
push:
paths-ignore: ['docs/**', 'docsrc/**', 'fittrackee_client/**', '*.md']
pull_request:
paths-ignore: ['docs/**', 'docsrc/**', 'fittrackee_client/**', '*.md']
env:
APP_SETTINGS: fittrackee.config.TestingConfig
DATABASE_TEST_URL: "postgresql://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
jobs:
python:
name: python ${{ matrix.python-version }}
runs-on: ubuntu-latest
container: python:${{ matrix.python-version }}
services:
postgres:
image: postgres:latest
env:
POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee
POSTGRES_PASSWORD: fittrackee
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
strategy:
matrix:
python-version: [ "3.7", "3.8", "3.9", "3.10" ]
steps:
- uses: actions/checkout@v2
- name: Install Poetry and Dependencies
run: |
python -m pip install --upgrade pip
pip install --quiet poetry
poetry config virtualenvs.create false
poetry install --no-interaction --quiet
- name: Bandit
if: matrix.python-version == '3.10'
run: bandit -r fittrackee -c pyproject.toml
- name: Lint
if: matrix.python-version == '3.10'
run: pytest --flake8 --isort --black -m "flake8 or isort or black" fittrackee e2e --ignore=fittrackee/migrations -p no:warnings
- name: Mypy
if: matrix.python-version == '3.10'
run: mypy fittrackee
- name: Pytest
run: pytest fittrackee -p no:warnings --cov fittrackee --cov-report term-missing
end2end:
runs-on: ubuntu-latest
needs: ["python"]
container: python:3.10
services:
postgres:
image: postgres:latest
env:
POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee
POSTGRES_PASSWORD: fittrackee
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
selenium:
image: selenium/standalone-firefox
mailhog:
image: mailhog/mailhog:latest
redis:
image: redis:latest
env:
APP_SETTINGS: fittrackee.config.End2EndTestingConfig
EMAIL_URL: "smtp://mailhog:1025"
REDIS_URL: "redis://redis:6379"
steps:
- uses: actions/checkout@v2
- name: Install Poetry and Dependencies
run: |
python -m pip install --upgrade pip
pip install --quiet poetry
poetry config virtualenvs.create false
poetry install --no-interaction --quiet
- name: Run migrations
run: flask db upgrade --directory fittrackee/migrations
- name: Start application and run tests with Selenium
run: |
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
nohup flask worker --processes=1 >> nohup.out 2>&1 &
pytest e2e --driver Remote --capability browserName firefox --host selenium --port 4444

View File

@ -1,100 +0,0 @@
image: python:3.9
variables:
POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee
POSTGRES_PASSWORD: fittrackee
POSTGRES_HOST: postgres
APP_SETTINGS: fittrackee.config.TestingConfig
DATABASE_TEST_URL: postgresql://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:
- lint
- 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
.javascript:
stage: tests
before_script:
- apt-get update && apt-get install -y nodejs npm
- npm install --global yarn
- cd fittrackee_client
- yarn install
python-lint:
stage: lint
extends: .python
script:
- pytest --flake8 --isort --black -m "flake8 or isort or black" fittrackee e2e --ignore=fittrackee/migrations
python-type-check:
stage: lint
extends: .python
script:
- mypy fittrackee
eslint:
stage: lint
extends: .javascript
script:
- yarn lint
python-3.7:
extends: .python
image: python:3.7
python-3.8:
extends: .python
image: python:3.8
python-3.9:
extends: .python
python-3.10:
extends: .python
image: python:3.10
typescript:
stage: tests
before_script:
- apt-get update && apt-get install -y nodejs npm
- npm install --global yarn
- cd fittrackee_client
- yarn install
script:
- yarn test:unit
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
- 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,5 +1,182 @@
# Change log # Change log
## Version 0.6.10 (2022/07/13)
### Issues Closed
#### Bugs Fixed
* [#210](https://github.com/SamR1/FitTrackee/issues/210) - ERROR - could not download 6 tiles
**Note**: for tile server requiring subdomains, see the new environment variable [`STATICMAP_SUBDOMAINS`](https://samr1.github.io/FitTrackee/installation.html#envvar-STATICMAP_SUBDOMAINS)
### Pull Requests
#### Bugs Fixed
* [#209](https://github.com/SamR1/FitTrackee/pull/209) - Incorrect duration with track containing multiple segments
Thanks to @gorgobacka
In this release 1 issue was closed.
## Version 0.6.9 (2022/07/03)
FitTrackee is now available in German (thanks to @gorgobacka).
And translations can be updated on Weblate.
### Issues Closed
#### Features
* [#200](https://github.com/SamR1/FitTrackee/issues/200) - Detect browser language to use matching translation if available
#### Bugs Fixed
* [PR#208](https://github.com/SamR1/FitTrackee/pull/208) - fix order on records cards
* [#201](https://github.com/SamR1/FitTrackee/issues/201) - html lang attribute is not updated when changing language
#### Translations
* [PR#197](https://github.com/SamR1/FitTrackee/pull/197) - Translations update from Weblate (French)
* [#196](https://github.com/SamR1/FitTrackee/issues/196) - Use translation management tool
* [#190](https://github.com/SamR1/FitTrackee/issues/190) - Add German translation
In this release 4 issues were closed.
Thanks to the contributors:
- @gorgobacka
- J. Lavoie (from Weblate)
## Version 0.6.8 (2022/06/22)
### Issues Closed
#### Bugs Fixed
* [#193](https://github.com/SamR1/FitTrackee/issues/193) - Allow deleting a workout when files are missing
* [#192](https://github.com/SamR1/FitTrackee/issues/192) - Returns 404 instead of 500 when map file not found
* [#191](https://github.com/SamR1/FitTrackee/issues/191) - Layout issue on Workouts page
### Misc
* change gpx and map file naming (included in [PR#195](https://github.com/SamR1/FitTrackee/pull/195))
Note: it does not affect previously imported files
* [cc4287e](https://github.com/SamR1/FitTrackee/commit/cc4287ed327faaba268a0c689841d16a7aecc3fb) - Fix docker env file
In this release 3 issues were closed.
## Version 0.6.7 (2022/06/11)
### Issues Closed
#### Bugs Fixed
* [#156](https://github.com/SamR1/FitTrackee/issues/156) - Process gpx file with offset
In this release 1 issue was closed.
## Version 0.6.6 (2022/05/29)
### Misc
No new features in this release, only dependencies update and code refacto before introducing new features.
## Version 0.6.5 (2022/04/24)
It is now possible to start FitTrackee without a configured SMTP provider (see [documentation](https://samr1.github.io/FitTrackee/installation.html#emails)).
It reduces pre-requisites for single-user instances.
To manage users, a new [CLI](https://samr1.github.io/FitTrackee/cli.html) is available.
### Issues Closed
#### Features
* [#180](https://github.com/SamR1/FitTrackee/issues/180) - allow using FitTrackee without SMTP server
In this release 1 issue was closed.
## Version 0.6.4 (2022/04/23)
### Issues Closed
#### Bugs Fixed
* [#178](https://github.com/SamR1/FitTrackee/issues/178) - cannot send email with TLS
In this release 1 issue was closed.
## Version 0.6.3 (2022/04/09)
### Pull Requests
#### Bugs Fixed
* [#177](https://github.com/SamR1/FitTrackee/pull/177) - Minor fixes
* add missing translation
* fix 'Add Workout' card position on small screens
## Version 0.6.2 (2022/04/03)
### Issues Closed
#### Bugs Fixed
* [#175](https://github.com/SamR1/FitTrackee/issues/175) - Distance card on dashboard is not refreshed
* [#173](https://github.com/SamR1/FitTrackee/issues/173) - link to user profile in workout card is incorrect
In this release 2 issues were closed.
## Version 0.6.1 (2022/03/27)
### Issues Closed
#### Bugs Fixed
* [#171](https://github.com/SamR1/FitTrackee/issues/171) - Stats chart is not updated correctly
In this release 1 issue was closed.
## Version 0.6.0 (2022/03/27)
This version introduces some changes on [user registration](https://samr1.github.io/FitTrackee/features.html#account-preferences).
From now on, a user needs to confirm his account after registration (an email with confirmation instructions is sent after registration).
### Issues Closed
#### Features
* [#155](https://github.com/SamR1/FitTrackee/issues/155) - Improve user registration
* [#106](https://github.com/SamR1/FitTrackee/issues/106) - Allow user to update email
#### Bugs Fixed
* [#169](https://github.com/SamR1/FitTrackee/issues/169) - user picture is not refreshed after update
### Pull Requests
#### Bugs Fixed
* [#161](https://github.com/SamR1/FitTrackee/pull/161) - Minor translation issue on 'Farthest'
* [#160](https://github.com/SamR1/FitTrackee/pull/160) - Minor translation issue on APP_ERROR
Thanks to @Fmstrat
In this release 3 issues were closed.
**Note:** This release contains database migration (see upgrade instructions in [documentation](https://samr1.github.io/FitTrackee/installation.html#upgrade))
## Version 0.5.7 (2022/02/13) ## Version 0.5.7 (2022/02/13)
This release contains several fixes including security fixes. This release contains several fixes including security fixes.

View File

@ -17,10 +17,22 @@ First off, thank you for your interest in contributing!
The **GitHub** repository contains: The **GitHub** repository contains:
- source code (note that the repository also includes client build), - source code (note that the repository also includes client build),
- translations,
- tests, - tests,
- documentation (source and build). - documentation (source and build).
Continuous integration pipeline runs on **Gitlab CI**. Continuous integration workflows run on **Github Actions** platform (on **push** and **pull requests**).
### Translations
The available languages are:
[![Translation status](https://hosted.weblate.org/widgets/fittrackee/-/multi-auto.svg)](https://hosted.weblate.org/engage/fittrackee/)
Translations files are located:
- on API side (emails): `fittrackee/emails/translations/` (implemented with [Babel](https://babel.pocoo.org/en/latest/))
- on client side: `fittrackee_client/src/locales` (implemented with [Vue I18n](https://vue-i18n.intlify.dev/))
Translations can be updated through [Weblate](https://hosted.weblate.org/engage/fittrackee/).
### How to install FitTrackee ### How to install FitTrackee
@ -50,29 +62,45 @@ Please make your changes from the development branch (`dev`).
``` ```
* Check the downgrade migration. * Check the downgrade migration.
* Run checks (lint, typecheck and tests). * Run checks (lint, type check and unit tests).
```shell ```shell
$ make check-all $ make check-all
``` ```
There are some end-to-end tests, to run them: There are some end-to-end tests, to run them (needs a running application):
```shell ```shell
$ make test-e2e $ make test-e2e
``` ```
Note: For now, pull requests from forks don't trigger pipelines on GitLab CI (see [current issue](https://gitlab.com/gitlab-org/gitlab/-/issues/5667)).
So make sure that checks don't return errors locally. * If needed, update translations.
* On client side, update files in `fittrackee_client/src/locales` folder.
* On API side (emails), to extract new strings into `messages.pot`:
```shell
$ make babel-extract
```
To add new strings in translations files (`fittrackee/emails/translations/<LANG>/LC_MESSAGES/messages.po`):
```shell
$ make babel-update
```
After updating strings in `messages.po`, compile the translations:
```shell
$ make babel-compile
```
* If needed, add or update tests. * If needed, add or update tests.
* If needed, update documentation. * If needed, update documentation (no need to build documentation, it will be done when releasing).
* If code contains client changes, you can generate a build, in a **separate commit** to ease code review. * If updated code contains client-side changes, you can generate javascript assets to check **FitTrackee** whithout starting client dev server:
```shell ```shell
$ make build-client $ make build-client
``` ```
No need to commit these files, dist files will be generated before merging or when releasing.
* Create your pull request to merge on `dev` branch. * Create your pull request to merge on `dev` branch.
* Ensure the pull requests description clearly describes the problem and solution. Include the relevant issue number if applicable. * Ensure the pull requests description clearly describes the problem and solution. Include the relevant issue number if applicable.
* If needed, [update your branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/keeping-your-pull-request-in-sync-with-the-base-branch).
Thanks. Thanks.

View File

@ -1,6 +1,4 @@
FROM python:3.9 FROM python:3.10
MAINTAINER SamR1@users.noreply.github.com
# set working directory # set working directory
RUN mkdir -p /usr/src/app RUN mkdir -p /usr/src/app

View File

@ -6,12 +6,29 @@ 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)
babel-extract:
$(PYBABEL) extract -F babel.cfg -k lazy_gettext -o messages.pot .
babel-init:
$(PYBABEL) init -i messages.pot -d fittrackee/emails/translations -l $(LANG)
babel-compile:
$(PYBABEL) compile -d fittrackee/emails/translations
babel-update:
$(PYBABEL) update -i messages.pot -d fittrackee/emails/translations
bandit:
$(BANDIT) -r fittrackee -c pyproject.toml
build-client: lint-client build-client: lint-client
cd fittrackee_client && $(NPM) build cd fittrackee_client && $(NPM) build
check-all: lint-all type-check test-python test-client check-all: bandit lint-all type-check test-all
check-python: lint-python type-check test-python check-client: lint-client test-client
check-python: bandit lint-python type-check test-python
clean: clean:
rm -rf .mypy_cache rm -rf .mypy_cache
@ -69,7 +86,7 @@ docker-stop:
docker-compose -f docker-compose-dev.yml stop docker-compose -f docker-compose-dev.yml stop
docker-up: docker-up:
docker-compose -f docker-compose-dev.yml up fittrackeee docker-compose -f docker-compose-dev.yml up fittrackee
downgrade-db: downgrade-db:
$(FLASK) db downgrade --directory $(MIGRATIONS) $(FLASK) db downgrade --directory $(MIGRATIONS)
@ -87,19 +104,21 @@ html:
install-db: install-db:
psql -U postgres -f db/create.sql psql -U postgres -f db/create.sql
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FTCLI) db upgrade
init-db: init-db:
$(FLASK) drop-db $(FTCLI) db drop
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FTCLI) db upgrade
install: install-client install-python install: install-client install-python
install-client: install-client:
cd fittrackee_client && $(NPM) install --prod # NPM_ARGS="--ignore-engines", if errors with Node latest version
cd fittrackee_client && $(NPM) install --prod $(NPM_ARGS)
install-client-dev: install-client-dev:
cd fittrackee_client && $(NPM) install # NPM_ARGS="--ignore-engines", if errors with Node latest version
cd fittrackee_client && $(NPM) install $(NPM_ARGS)
install-dev: install-client-dev install-python-dev install-dev: install-client-dev install-python-dev
@ -162,11 +181,14 @@ serve-python-dev:
$(FLASK) run --with-threads -h $(HOST) -p $(PORT) --cert=adhoc $(FLASK) run --with-threads -h $(HOST) -p $(PORT) --cert=adhoc
set-admin: set-admin:
$(FLASK) users set-admin $(USERNAME) echo "Deprecated command, will be removed in a next version. Use 'user-set-admin' instead."
$(FTCLI) users update $(USERNAME) --set-admin true
test-e2e: test-e2e:
$(PYTEST) e2e --driver firefox $(PYTEST_ARGS) $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
test-all: test-client test-python
test-e2e-client: test-e2e-client:
E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS) E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
@ -181,4 +203,17 @@ type-check:
$(MYPY) fittrackee $(MYPY) fittrackee
upgrade-db: upgrade-db:
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FTCLI) db upgrade
user-activate:
$(FTCLI) users update $(USERNAME) --activate
user-reset-password:
$(FTCLI) users update $(USERNAME) --reset-password
ADMIN := true
user-set-admin:
$(FTCLI) users update $(USERNAME) --set-admin $(ADMIN)
user-update-email:
$(FTCLI) users update $(USERNAME) --update-email $(EMAIL)

View File

@ -2,15 +2,12 @@ export HOST = 0.0.0.0
export PORT = 5000 export PORT = 5000
export CLIENT_PORT = 3000 export CLIENT_PORT = 3000
export FLASK_APP = $(PWD)/fittrackee/__main__.py
export MIGRATIONS = $(PWD)/fittrackee/migrations export MIGRATIONS = $(PWD)/fittrackee/migrations
export APP_WORKERS = 1 export APP_WORKERS = 1
export WORKERS_PROCESSES = 1 export WORKERS_PROCESSES = 1
# for dev env # for dev env
export FLASK_ENV = development export FLASK_ENV = development
export APP_SETTINGS = fittrackee.config.DevelopmentConfig
export DATABASE_URL = postgresql://fittrackee:fittrackee@$(HOST):5432/fittrackee
export DATABASE_TEST_URL = postgresql://fittrackee:fittrackee@$(HOST):5432/fittrackee_test export DATABASE_TEST_URL = postgresql://fittrackee:fittrackee@$(HOST):5432/fittrackee_test
export TEST_APP_URL = http://$(HOST):$(PORT) export TEST_APP_URL = http://$(HOST):$(PORT)
export TEST_CLIENT_URL = http://$(HOST):$(CLIENT_PORT) export TEST_CLIENT_URL = http://$(HOST):$(CLIENT_PORT)
@ -26,6 +23,9 @@ PYTEST = $(VENV)/bin/py.test -c pyproject.toml -W ignore::DeprecationWarning
GUNICORN = $(VENV)/bin/gunicorn GUNICORN = $(VENV)/bin/gunicorn
BLACK = $(VENV)/bin/black BLACK = $(VENV)/bin/black
MYPY = $(VENV)/bin/mypy MYPY = $(VENV)/bin/mypy
BANDIT = $(VENV)/bin/bandit
PYBABEL = $(VENV)/bin/pybabel
FTCLI = $(VENV)/bin/ftcli
# Node env # Node env
NODE_MODULES = $(PWD)/fittrackee_client/node_modules NODE_MODULES = $(PWD)/fittrackee_client/node_modules

View File

@ -3,15 +3,15 @@
[![PyPI version](https://img.shields.io/pypi/v/fittrackee.svg)](https://pypi.org/project/fittrackee/) [![PyPI version](https://img.shields.io/pypi/v/fittrackee.svg)](https://pypi.org/project/fittrackee/)
[![Python Version](https://img.shields.io/badge/python-3.7+-brightgreen.svg)](https://python.org) [![Python Version](https://img.shields.io/badge/python-3.7+-brightgreen.svg)](https://python.org)
[![Flask Version](https://img.shields.io/badge/flask-2.0-brightgreen.svg)](http://flask.pocoo.org/) [![Flask Version](https://img.shields.io/badge/flask-2.1-brightgreen.svg)](http://flask.pocoo.org/)
[![code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black) [![code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black)
[![type check: mypy](https://img.shields.io/badge/type%20check-mypy-blue)](http://mypy-lang.org/) [![type check: mypy](https://img.shields.io/badge/type%20check-mypy-blue)](http://mypy-lang.org/)
[![Vue Version](https://img.shields.io/badge/vue-3.2-brightgreen.svg)](https://v3.vuejs.org/) [![Vue Version](https://img.shields.io/badge/vue-3.2-brightgreen.svg)](https://v3.vuejs.org/)
[![Typescript Version](https://img.shields.io/npm/types/typescript)](https://www.typescriptlang.org/) [![Typescript Version](https://img.shields.io/npm/types/typescript)](https://www.typescriptlang.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) [![pipeline status](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-python.yml/badge.svg)](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-python.yml)
[![pipeline status](https://gitlab.com/SamR1/FitTrackee/badges/master/pipeline.svg)](https://gitlab.com/SamR1/FitTrackee/-/commits/master) [![pipeline status](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-javascript.yml/badge.svg)](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-javascript.yml)
[![coverage report](https://gitlab.com/SamR1/FitTrackee/badges/master/coverage.svg)](https://gitlab.com/SamR1/FitTrackee/-/commits/master) <sup><sup>1</sup></sup> [![translation status](https://hosted.weblate.org/widgets/fittrackee/-/svg-badge.svg)](https://hosted.weblate.org/engage/fittrackee/)
--- ---
@ -26,12 +26,11 @@ Examples for Android (non-exhaustive list):
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.
Translations can be updated through [Weblate](https://hosted.weblate.org/engage/fittrackee/).
Available languages:
[![Translation status](https://hosted.weblate.org/widgets/fittrackee/-/multi-auto.svg)](https://hosted.weblate.org/engage/fittrackee/)
**Still under heavy development (some features may be unstable).** **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 Screenshot](https://samr1.github.io/FitTrackee/_images/fittrackee_screenshot-01.png) ![FitTrackee Dashboard Screenshot](https://samr1.github.io/FitTrackee/_images/fittrackee_screenshot-01.png)
---
Notes:
_1. Test coverage: only for Python API_

5
SECURITY.md Normal file
View File

@ -0,0 +1,5 @@
# Security Policy
## Reporting a Vulnerability
Please report suspected security vulnerabilities to `samr1.dev [at] pm.me`.

View File

@ -1 +1 @@
0.5.7 0.6.10

5
babel.cfg Normal file
View File

@ -0,0 +1,5 @@
[jinja2: fittrackee/emails/templates/**.html]
silent=False
[jinja2: fittrackee/emails/templates/**.txt]
silent=False

View File

@ -1,5 +1,3 @@
FROM postgres:13 FROM postgres:13
MAINTAINER SamR1@users.noreply.github.com
COPY create.sql /docker-entrypoint-initdb.d COPY create.sql /docker-entrypoint-initdb.d

View File

@ -19,7 +19,7 @@ services:
ports: ports:
- "5000:5000" - "5000:5000"
env_file: env_file:
- .env.docker - .env
depends_on: depends_on:
- fittrackee-db - fittrackee-db
- redis - redis

View File

@ -4,5 +4,5 @@ cd /usr/src/app
source .env.docker source .env.docker
flask drop-db ftcli db drop
flask db upgrade --directory fittrackee/migrations ftcli db upgrade

View File

@ -4,4 +4,4 @@ cd /usr/src/app
source .env.docker source .env.docker
flask users set-admin $1 ftcli users update $1 --set-admin true

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: 1e2841616c48de88a07f12a07138022e config: c52394c093f45e0ad0599926c90fff71
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 KiB

After

Width:  |  Height:  |  Size: 369 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -4,8 +4,9 @@ Authentication
.. autoflask:: fittrackee:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
auth.register_user, auth.register_user,
auth.confirm_account,
auth.resend_account_confirmation_email,
auth.login_user, auth.login_user,
auth.logout_user,
auth.get_authenticated_user_profile, auth.get_authenticated_user_profile,
auth.edit_user, auth.edit_user,
auth.edit_user_preferences, auth.edit_user_preferences,
@ -14,4 +15,6 @@ Authentication
auth.edit_picture, auth.edit_picture,
auth.del_picture, auth.del_picture,
auth.request_password_reset, auth.request_password_reset,
auth.update_password auth.update_user_account,
auth.update_password,
auth.update_email

View File

@ -1,5 +1,182 @@
# Change log # Change log
## Version 0.6.10 (2022/07/13)
### Issues Closed
#### Bugs Fixed
* [#210](https://github.com/SamR1/FitTrackee/issues/210) - ERROR - could not download 6 tiles
**Note**: for tile server requiring subdomains, see the new environment variable [`STATICMAP_SUBDOMAINS`](https://samr1.github.io/FitTrackee/installation.html#envvar-STATICMAP_SUBDOMAINS)
### Pull Requests
#### Bugs Fixed
* [#209](https://github.com/SamR1/FitTrackee/pull/209) - Incorrect duration with track containing multiple segments
Thanks to @gorgobacka
In this release 1 issue was closed.
## Version 0.6.9 (2022/07/03)
FitTrackee is now available in German (thanks to @gorgobacka).
And translations can be updated on Weblate.
### Issues Closed
#### Features
* [#200](https://github.com/SamR1/FitTrackee/issues/200) - Detect browser language to use matching translation if available
#### Bugs Fixed
* [PR#208](https://github.com/SamR1/FitTrackee/pull/208) - fix order on records cards
* [#201](https://github.com/SamR1/FitTrackee/issues/201) - html lang attribute is not updated when changing language
#### Translations
* [PR#197](https://github.com/SamR1/FitTrackee/pull/197) - Translations update from Weblate (French)
* [#196](https://github.com/SamR1/FitTrackee/issues/196) - Use translation management tool
* [#190](https://github.com/SamR1/FitTrackee/issues/190) - Add German translation
In this release 4 issues were closed.
Thanks to the contributors:
- @gorgobacka
- J. Lavoie (from Weblate)
## Version 0.6.8 (2022/06/22)
### Issues Closed
#### Bugs Fixed
* [#193](https://github.com/SamR1/FitTrackee/issues/193) - Allow deleting a workout when files are missing
* [#192](https://github.com/SamR1/FitTrackee/issues/192) - Returns 404 instead of 500 when map file not found
* [#191](https://github.com/SamR1/FitTrackee/issues/191) - Layout issue on Workouts page
### Misc
* change gpx and map file naming (included in [PR#195](https://github.com/SamR1/FitTrackee/pull/195))
Note: it does not affect previously imported files
* [cc4287e](https://github.com/SamR1/FitTrackee/commit/cc4287ed327faaba268a0c689841d16a7aecc3fb) - Fix docker env file
In this release 3 issues were closed.
## Version 0.6.7 (2022/06/11)
### Issues Closed
#### Bugs Fixed
* [#156](https://github.com/SamR1/FitTrackee/issues/156) - Process gpx file with offset
In this release 1 issue was closed.
## Version 0.6.6 (2022/05/29)
### Misc
No new features in this release, only dependencies update and code refacto before introducing new features.
## Version 0.6.5 (2022/04/24)
It is now possible to start FitTrackee without a configured SMTP provider (see [documentation](https://samr1.github.io/FitTrackee/installation.html#emails)).
It reduces pre-requisites for single-user instances.
To manage users, a new [CLI](https://samr1.github.io/FitTrackee/cli.html) is available.
### Issues Closed
#### Features
* [#180](https://github.com/SamR1/FitTrackee/issues/180) - allow using FitTrackee without SMTP server
In this release 1 issue was closed.
## Version 0.6.4 (2022/04/23)
### Issues Closed
#### Bugs Fixed
* [#178](https://github.com/SamR1/FitTrackee/issues/178) - cannot send email with TLS
In this release 1 issue was closed.
## Version 0.6.3 (2022/04/09)
### Pull Requests
#### Bugs Fixed
* [#177](https://github.com/SamR1/FitTrackee/pull/177) - Minor fixes
* add missing translation
* fix 'Add Workout' card position on small screens
## Version 0.6.2 (2022/04/03)
### Issues Closed
#### Bugs Fixed
* [#175](https://github.com/SamR1/FitTrackee/issues/175) - Distance card on dashboard is not refreshed
* [#173](https://github.com/SamR1/FitTrackee/issues/173) - link to user profile in workout card is incorrect
In this release 2 issues were closed.
## Version 0.6.1 (2022/03/27)
### Issues Closed
#### Bugs Fixed
* [#171](https://github.com/SamR1/FitTrackee/issues/171) - Stats chart is not updated correctly
In this release 1 issue was closed.
## Version 0.6.0 (2022/03/27)
This version introduces some changes on [user registration](https://samr1.github.io/FitTrackee/features.html#account-preferences).
From now on, a user needs to confirm his account after registration (an email with confirmation instructions is sent after registration).
### Issues Closed
#### Features
* [#155](https://github.com/SamR1/FitTrackee/issues/155) - Improve user registration
* [#106](https://github.com/SamR1/FitTrackee/issues/106) - Allow user to update email
#### Bugs Fixed
* [#169](https://github.com/SamR1/FitTrackee/issues/169) - user picture is not refreshed after update
### Pull Requests
#### Bugs Fixed
* [#161](https://github.com/SamR1/FitTrackee/pull/161) - Minor translation issue on 'Farthest'
* [#160](https://github.com/SamR1/FitTrackee/pull/160) - Minor translation issue on APP_ERROR
Thanks to @Fmstrat
In this release 3 issues were closed.
**Note:** This release contains database migration (see upgrade instructions in [documentation](https://samr1.github.io/FitTrackee/installation.html#upgrade))
## Version 0.5.7 (2022/02/13) ## Version 0.5.7 (2022/02/13)
This release contains several fixes including security fixes. This release contains several fixes including security fixes.

67
docs/_sources/cli.rst.txt Normal file
View File

@ -0,0 +1,67 @@
Command line interface
######################
A command line interface (CLI) is available to manage database and users.
.. code-block:: bash
$ ftcli
Usage: ftcli [OPTIONS] COMMAND [ARGS]...
FitTrackee Command Line Interface
Options:
--help Show this message and exit.
Commands:
db Manage database.
users Manage users.
.. warning::
| The following commands are now deprecated and will be removed in a next version:
| - ``fittrackee_set_admin``
| - ``fittrackee_upgrade_db``
Database
~~~~~~~~
``ftcli db upgrade``
""""""""""""""""""""
.. versionadded:: 0.6.5
Apply migrations.
``ftcli db drop``
"""""""""""""""""
.. versionadded:: 0.6.5
Empty database and delete uploaded files, only on development environments.
Users
~~~~~
``ftcli users update``
""""""""""""""""""""""
.. versionadded:: 0.6.5
Modify a user account (admin rights, active status, email and password).
.. cssclass:: table-bordered
.. list-table::
:widths: 25 50
:header-rows: 1
* - Options
- Description
* - ``--set-admin BOOLEAN``
- Add/remove admin rights (when adding admin rights, it also activates user account if not active).
* - ``--activate``
- Activate user account.
* - ``--reset-password``
- Reset user password (a new password will be displayed).
* - ``--update-email EMAIL``
- Update user email.

View File

@ -44,9 +44,13 @@ Workouts
- average speed (**new in 0.5.1**) - average speed (**new in 0.5.1**)
- User records by sports: - User records by sports:
- average speed - average speed
- farest distance - farthest distance
- longest duration - longest duration
- maximum speed - maximum speed
.. note::
Records may differ from records displayed by the application that originally generated the gpx files.
- Workouts list and filter. Only sports with workouts are displayed in sport dropdown. - Workouts list and filter. Only sports with workouts are displayed in sport dropdown.
.. note:: .. note::
@ -55,9 +59,17 @@ Workouts
Account & preferences Account & preferences
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
- A user can create, update and deleted his account - A user can create, update and deleted his account.
- On registration, the user account is created with selected language in dropdown as user preference (*new in 0.6.9*).
- After registration, the user account is inactive and an email with confirmation instructions is sent to activate it.
A user with an inactive account cannot log in. (*new in 0.6.0*)
.. note::
In case email sending is not configured, a `command line <cli.html#ftcli-users-update>`__ allows to activate users account.
- A user can set language, timezone and first day of week. - A user can set language, timezone and first day of week.
- A user can reset his password (*new in 0.3.0*) - A user can reset his password (*new in 0.3.0*)
- A user can change his email address (*new in 0.6.0*)
- A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*) - A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*)
- A user can set sport preferences (*new in 0.5.0*): - A user can set sport preferences (*new in 0.5.0*):
- change sport color (used for sport image and charts) - change sport color (used for sport image and charts)
@ -82,15 +94,23 @@ Administration
- maximum size of uploaded files - maximum size of uploaded files
- maximum size of zip archive - maximum size of zip archive
- maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors. - maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.
- administrator email for contact (*new in 0.6.0*)
.. warning:: .. warning::
Updating server configuration may be necessary to handle large files (like `nginx <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_ for instance). Updating server configuration may be necessary to handle large files (like `nginx <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_ for instance).
.. note::
If email sending is disabled, a warning is displayed.
- **Users** - **Users**
- display users list and details - display and filter users list
- edit a user to add/remove administration rights - edit a user to:
- add/remove administration rights
- activate his account (*new in 0.6.0*)
- update his email (in case his account is locked) (*new in 0.6.0*)
- reset his password (in case his account is locked) (*new in 0.6.0*). If email sending is disabled, it is only possible via CLI.
- delete a user - delete a user
- **Sports** - **Sports**
@ -100,7 +120,9 @@ Administration
Translations Translations
^^^^^^^^^^^^ ^^^^^^^^^^^^
FitTrackee is available in English and French (which can be saved in the user preferences). FitTrackee is available in the following languages (which can be saved in the user preferences):
.. figure:: https://hosted.weblate.org/widgets/fittrackee/-/multi-auto.svg
Screenshots Screenshots

View File

@ -34,6 +34,7 @@ Table of contents
features features
installation installation
cli
api/index api/index
troubleshooting/index troubleshooting/index
changelog changelog

View File

@ -14,17 +14,17 @@ This application is written in Python (API) and Typescript (client):
- `Leaflet <https://leafletjs.com/>`__ to display map - `Leaflet <https://leafletjs.com/>`__ to display map
- `Chart.js <https://www.chartjs.org/>`__ to display charts with elevation and speed - `Chart.js <https://www.chartjs.org/>`__ to display charts with elevation and speed
Logo, sports and weather icons are made by `Freepik <https://www.freepik.com/>`__ from `www.flaticon.com <https://www.flaticon.com/>`__. | Logo, some sports and weather icons are made by `Freepik <https://www.freepik.com/>`__ from `www.flaticon.com <https://www.flaticon.com/>`__.
| FitTrackee also uses icons from `Fork Awesome <https://forkaweso.me>`__.
Prerequisites Prerequisites
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
- PostgreSQL database (10+)
- Redis for task queue
- Python 3.7+ - Python 3.7+
- PostgreSQL database (10+)
- SMTP provider and Redis for task queue (if email sending is enabled)
- API key from `Dark Sky <https://darksky.net/dev>`__ (not mandatory)
- `Poetry <https://poetry.eustace.io>`__ (for installation from sources only) - `Poetry <https://poetry.eustace.io>`__ (for installation from sources only)
- API key from `Dark Sky <https://darksky.net/dev>`__ [not mandatory]
- SMTP provider
- `Yarn <https://yarnpkg.com>`__ (for development only) - `Yarn <https://yarnpkg.com>`__ (for development only)
- Docker and Docker Compose (for development or evaluation purposes) - Docker and Docker Compose (for development or evaluation purposes)
@ -95,9 +95,9 @@ deployment method.
.. versionadded:: 0.4.0 .. versionadded:: 0.4.0
Directory containing uploaded files. **Absolute path** to the directory where `uploads` folder will be created.
:default: `fittrackee/uploads/` :default: `<application_directory>/fittrackee`
.. danger:: .. danger::
| With installation from PyPI, the directory will be located in | With installation from PyPI, the directory will be located in
@ -108,7 +108,7 @@ deployment method.
| Database URL with username and password, must be initialized in production environment. | Database URL with username and password, must be initialized in production environment.
| For example in dev environment : ``postgresql://fittrackee:fittrackee@localhost:5432/fittrackee`` | For example in dev environment : ``postgresql://fittrackee:fittrackee@localhost:5432/fittrackee``
.. danger:: .. warning::
| Since `SQLAlchemy update (1.4+) <https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b>`__, | Since `SQLAlchemy update (1.4+) <https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b>`__,
engine URL should begin with `postgresql://`. engine URL should begin with `postgresql://`.
@ -132,6 +132,13 @@ deployment method.
Email URL with credentials, see `Emails <installation.html#emails>`__. Email URL with credentials, see `Emails <installation.html#emails>`__.
.. versionchanged:: 0.6.5
:default: empty string
.. danger::
If the email URL is empty, email sending will be disabled.
.. warning:: .. warning::
If the email URL is invalid, the application may not start. If the email URL is invalid, the application may not start.
@ -168,6 +175,16 @@ deployment method.
:default: `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png` :default: `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`
.. envvar:: STATICMAP_SUBDOMAINS 🆕
.. versionadded:: 0.6.10
| Some tile servers require a subdomain, see `Map tile server <installation.html#map-tile-server>`__.
| For instance: "a,b,c" for OSM France.
:default: empty string
.. envvar:: MAP_ATTRIBUTION .. envvar:: MAP_ATTRIBUTION
.. versionadded:: 0.4.0 .. versionadded:: 0.4.0
@ -177,11 +194,17 @@ deployment method.
:default: `&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors` :default: `&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`
.. envvar:: DEFAULT_STATICMAP 🆕 .. envvar:: DEFAULT_STATICMAP
.. versionadded:: 0.4.9 .. versionadded:: 0.4.9
If `True`, it keeps using default tile server to generate static maps. | If `True`, it keeps using default tile server to generate static maps (Komoot.de tile server).
| Otherwise, it uses the tile server set in `TILE_SERVER_URL <installation.html#envvar-TILE_SERVER_URL>`__.
.. versionchanged:: 0.6.10
| This variable is now case-insensitive.
| If `False`, depending on tile server, `subdomains <installation.html#envvar-STATICMAP_SUBDOMAINS>`__ may be mandatory.
:default: False :default: False
@ -209,12 +232,31 @@ To send emails, a valid ``EMAIL_URL`` must be provided:
- with SSL: ``smtp://username:password@smtp.example.com:465/?ssl=True`` - with SSL: ``smtp://username:password@smtp.example.com:465/?ssl=True``
- with STARTTLS: ``smtp://username:password@smtp.example.com:587/?tls=True`` - with STARTTLS: ``smtp://username:password@smtp.example.com:587/?tls=True``
.. warning::
| - If the email URL is invalid, the application may not start.
| - Sending emails with Office365 may not work if SMTP auth is disabled.
.. versionadded:: 0.5.3 .. versionchanged:: 0.5.3
| Credentials can be omitted: ``smtp://smtp.example.com:25``. | Credentials can be omitted: ``smtp://smtp.example.com:25``.
| If ``:<port>`` is omitted, the port defaults to 25. | If ``:<port>`` is omitted, the port defaults to 25.
.. warning::
| Since 0.6.0, newly created accounts must be confirmed (an email with confirmation instructions is sent after registration).
Emails sent by FitTrackee are:
- account confirmation instructions
- password reset request
- email change (to old and new email adresses)
- password change
.. versionchanged:: 0.6.5
| For single-user instance, it is possible to disable email sending with an empty ``EMAIL_URL`` (in this case, no need to start dramatiq workers).
| A `CLI <cli.html#ftcli-users-update>`__ is available to activate account and modify email and password.
Map tile server Map tile server
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
.. versionadded:: 0.4.0 .. versionadded:: 0.4.0
@ -230,6 +272,20 @@ To keep using **ThunderForest Outdoors**, the configuration is:
.. note:: .. note::
| Check the terms of service of tile provider for map attribution | Check the terms of service of tile provider for map attribution
.. versionchanged:: 0.6.10
Since the tile server can be used for static map generation, some servers require a subdomain.
For instance, to set OSM France tile server, the expected values are:
- ``TILE_SERVER_URL=https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png``
- ``MAP_ATTRIBUTION='fond de carte par <a href="http://www.openstreetmap.fr/mentions-legales/" target="_blank" rel="nofollow noopener">OpenStreetMap France</a>, sous&nbsp;<a href="http://creativecommons.org/licenses/by-sa/2.0/fr/" target="_blank" rel="nofollow noopener">licence CC BY-SA</a>'``
- ``STATICMAP_SUBDOMAINS=a,b,c``
The subdomain will be chosen randomly.
Installation Installation
~~~~~~~~~~~~ ~~~~~~~~~~~~
@ -273,7 +329,7 @@ For instance, copy and update ``.env`` file from ``.env.example`` and source the
.. code-block:: bash .. code-block:: bash
$ fittrackee_upgrade_db $ ftcli db upgrade
- Start the application - Start the application
@ -281,7 +337,7 @@ For instance, copy and update ``.env`` file from ``.env.example`` and source the
$ fittrackee $ fittrackee
- Start task queue workers - Start task queue workers if email sending is enabled.
.. code-block:: bash .. code-block:: bash
@ -292,12 +348,14 @@ For instance, copy and update ``.env`` file from ``.env.example`` and source the
- Open http://localhost:3000 and register - Open http://localhost:3000 and register
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ fittrackee_set_admin <username> $ ftcli users update <username> --set-admin true
.. note::
If the user account is inactive, it activates it.
From sources From sources
^^^^^^^^^^^^ ^^^^^^^^^^^^
@ -352,12 +410,14 @@ Dev environment
- Open http://localhost:3000 and register - Open http://localhost:3000 and register
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ make set-admin USERNAME=<username> $ make user-set-admin USERNAME=<username>
.. note::
If the user account is inactive, it activates it.
Production environment Production environment
"""""""""""""""""""""" """"""""""""""""""""""
@ -365,13 +425,13 @@ Production environment
.. warning:: .. warning::
| Note that FitTrackee is under heavy development, some features may be unstable. | Note that FitTrackee is under heavy development, some features may be unstable.
- Download the last release (for now, it is the release v0.5.7): - Download the last release (for now, it is the release v0.6.10):
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.5.7.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.10.tar.gz
$ tar -xzf v0.5.7.tar.gz $ tar -xzf v0.6.10.tar.gz
$ mv FitTrackee-0.5.7 FitTrackee $ mv FitTrackee-0.6.10 FitTrackee
$ cd FitTrackee $ cd FitTrackee
- Create **.env** from example and update it - Create **.env** from example and update it
@ -396,14 +456,19 @@ Production environment
$ make run $ make run
.. note::
If email sending is disabled: ``$ make run-server``
- Open http://localhost:5000 and register - Open http://localhost:5000 and register
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ make set-admin USERNAME=<username> $ make user-set-admin USERNAME=<username>
.. note::
If the user account is inactive, it activates it.
Upgrade Upgrade
~~~~~~~ ~~~~~~~
@ -417,7 +482,7 @@ Upgrade
From PyPI From PyPI
^^^^^^^^^ ^^^^^^^^^
- Activate the virtualenv - Stop the application and activate the virtualenv
- Upgrade with pip - Upgrade with pip
@ -436,10 +501,9 @@ From PyPI
.. code-block:: bash .. code-block:: bash
$ fittrackee_upgrade_db $ ftcli db upgrade
- Restart the application and task queue workers (if email sending is enabled).
- Restart the application and task queue workers.
From sources From sources
@ -487,13 +551,13 @@ Prod environment
- Change to the directory where FitTrackee directory is located - Change to the directory where FitTrackee directory is located
- Download the last release (for now, it is the release v0.5.7) and overwrite existing files: - Download the last release (for now, it is the release v0.6.10) and overwrite existing files:
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.5.7.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.10.tar.gz
$ tar -xzf v0.5.7.tar.gz $ tar -xzf v0.6.10.tar.gz
$ cp -R FitTrackee-0.5.7/* FitTrackee/ $ cp -R FitTrackee-0.6.10/* FitTrackee/
$ cd FitTrackee $ cd FitTrackee
- Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__). - Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__).
@ -516,6 +580,8 @@ Prod environment
$ make run $ make run
.. note::
If email sending is disabled: ``$ make run-server``
Deployment Deployment
~~~~~~~~~~ ~~~~~~~~~~
@ -554,6 +620,7 @@ Examples (to update depending on your application configuration and given distri
Environment="SENDER_EMAIL=" Environment="SENDER_EMAIL="
Environment="REDIS_URL=" Environment="REDIS_URL="
Environment="TILE_SERVER_URL=" Environment="TILE_SERVER_URL="
Environment="STATICMAP_SUBDOMAINS="
Environment="MAP_ATTRIBUTION=" Environment="MAP_ATTRIBUTION="
Environment="WEATHER_API_KEY=" Environment="WEATHER_API_KEY="
WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY> WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY>
@ -641,8 +708,7 @@ Installation
.. versionadded:: 0.4.4 .. versionadded:: 0.4.4
For evaluation purposes , docker files are available, For evaluation purposes, docker files are available, installing **FitTrackee** from **sources**.
installing **FitTrackee** from **sources**.
- To install **FitTrackee** with database initialisation and run the application and dramatiq workers: - To install **FitTrackee** with database initialisation and run the application and dramatiq workers:
@ -650,18 +716,22 @@ installing **FitTrackee** from **sources**.
$ git clone https://github.com/SamR1/FitTrackee.git $ git clone https://github.com/SamR1/FitTrackee.git
$ cd FitTrackee $ cd FitTrackee
$ cp .env.docker .env
$ make docker-build docker-run docker-init $ make docker-build docker-run docker-init
Open http://localhost:5000 and register. Open http://localhost:5000 and register.
Open http://localhost:8025 to access `MailHog interface <https://github.com/mailhog/MailHog>`_ (email testing tool) Open http://localhost:8025 to access `MailHog interface <https://github.com/mailhog/MailHog>`_ (email testing tool)
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ make docker-set-admin USERNAME=<username> $ make docker-set-admin USERNAME=<username>
.. note::
If the user account is inactive, it activates it.
- To stop **Fittrackee**: - To stop **Fittrackee**:
.. code-block:: bash .. code-block:: bash

View File

@ -5,10 +5,24 @@ Administrator
`FitTrackee fails to start` `FitTrackee fails to start`
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Check the database URL in `Environment variables <../installation.html#envvar-DATABASE_URL>`__ if the following error is displayed in **gunicorn** logs: - Check the database URL in `environment variables <../installation.html#envvar-DATABASE_URL>`__ if the following error is displayed in **gunicorn** logs:
.. code:: .. code::
sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres
It must start with `postgresql://` (engine URLs starting with `postgres://` are no longer supported). It must start with `postgresql://` (engine URLs starting with `postgres://` are no longer supported).
- Check the email URL in `environment variables <../installation.html#envvar-EMAIL_URL>`__ if the following error is displayed in **gunicorn** logs:
.. code::
fittrackee.emails.exceptions.InvalidEmailUrlScheme
A valid ``EMAIL_URL`` must be provided (see `emails <../installation.html#emails>`__).
`Map images are not displayed but map is shown in Workout detail`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Check the path in `environment variables <../installation.html#envvar-UPLOAD_FOLDER>`__. ``UPLOAD_FOLDER`` must be set with an absolute path.

View File

@ -3,7 +3,6 @@ Troubleshooting
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: Endpoints:
administrator administrator
user user

View File

@ -0,0 +1,134 @@
/*
* _sphinx_javascript_frameworks_compat.js
* ~~~~~~~~~~
*
* Compatability shim for jQuery and underscores.js.
*
* WILL BE REMOVED IN Sphinx 6.0
* xref RemovedInSphinx60Warning
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* small helper function to urldecode strings
*
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
*/
jQuery.urldecode = function(x) {
if (!x) {
return x
}
return decodeURIComponent(x.replace(/\+/g, ' '));
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node, addItems) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else {
span = document.createElement("span");
span.className = className;
}
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
var bbox = node.parentElement.getBBox();
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
addItems.push({
"parent": node.parentNode,
"target": rect});
}
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this, addItems);
});
}
}
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}

View File

@ -222,7 +222,7 @@ table.modindextable td {
/* -- general body styles --------------------------------------------------- */ /* -- general body styles --------------------------------------------------- */
div.body { div.body {
min-width: 450px; min-width: 360px;
max-width: 800px; max-width: 800px;
} }
@ -237,16 +237,6 @@ a.headerlink {
visibility: hidden; visibility: hidden;
} }
a.brackets:before,
span.brackets > a:before{
content: "[";
}
a.brackets:after,
span.brackets > a:after {
content: "]";
}
h1:hover > a.headerlink, h1:hover > a.headerlink,
h2:hover > a.headerlink, h2:hover > a.headerlink,
h3:hover > a.headerlink, h3:hover > a.headerlink,
@ -334,12 +324,16 @@ aside.sidebar {
p.sidebar-title { p.sidebar-title {
font-weight: bold; font-weight: bold;
} }
nav.contents,
aside.topic,
div.admonition, div.topic, blockquote { div.admonition, div.topic, blockquote {
clear: left; clear: left;
} }
/* -- topics ---------------------------------------------------------------- */ /* -- topics ---------------------------------------------------------------- */
nav.contents,
aside.topic,
div.topic { div.topic {
border: 1px solid #ccc; border: 1px solid #ccc;
@ -379,6 +373,9 @@ div.body p.centered {
div.sidebar > :last-child, div.sidebar > :last-child,
aside.sidebar > :last-child, aside.sidebar > :last-child,
nav.contents > :last-child,
aside.topic > :last-child,
div.topic > :last-child, div.topic > :last-child,
div.admonition > :last-child { div.admonition > :last-child {
margin-bottom: 0; margin-bottom: 0;
@ -386,6 +383,9 @@ div.admonition > :last-child {
div.sidebar::after, div.sidebar::after,
aside.sidebar::after, aside.sidebar::after,
nav.contents::after,
aside.topic::after,
div.topic::after, div.topic::after,
div.admonition::after, div.admonition::after,
blockquote::after { blockquote::after {
@ -428,10 +428,6 @@ table.docutils td, table.docutils th {
border-bottom: 1px solid #aaa; border-bottom: 1px solid #aaa;
} }
table.footnote td, table.footnote th {
border: 0 !important;
}
th { th {
text-align: left; text-align: left;
padding-right: 5px; padding-right: 5px;
@ -615,6 +611,7 @@ ul.simple p {
margin-bottom: 0; margin-bottom: 0;
} }
/* Docutils 0.17 and older (footnotes & citations) */
dl.footnote > dt, dl.footnote > dt,
dl.citation > dt { dl.citation > dt {
float: left; float: left;
@ -632,6 +629,33 @@ dl.citation > dd:after {
clear: both; clear: both;
} }
/* Docutils 0.18+ (footnotes & citations) */
aside.footnote > span,
div.citation > span {
float: left;
}
aside.footnote > span:last-of-type,
div.citation > span:last-of-type {
padding-right: 0.5em;
}
aside.footnote > p {
margin-left: 2em;
}
div.citation > p {
margin-left: 4em;
}
aside.footnote > p:last-of-type,
div.citation > p:last-of-type {
margin-bottom: 0em;
}
aside.footnote > p:last-of-type:after,
div.citation > p:last-of-type:after {
content: "";
clear: both;
}
/* Footnotes & citations ends */
dl.field-list { dl.field-list {
display: grid; display: grid;
grid-template-columns: fit-content(30%) auto; grid-template-columns: fit-content(30%) auto;

View File

@ -2,325 +2,263 @@
* doctools.js * doctools.js
* ~~~~~~~~~~~ * ~~~~~~~~~~~
* *
* Sphinx JavaScript utilities for all documentation. * Base JavaScript utilities for all Sphinx HTML documentation.
* *
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details. * :license: BSD, see LICENSE for details.
* *
*/ */
"use strict";
/** const _ready = (callback) => {
* select a different prefix for underscore if (document.readyState !== "loading") {
*/ callback();
$u = _.noConflict(); } else {
document.addEventListener("DOMContentLoaded", callback);
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
*/
jQuery.urldecode = function(x) {
if (!x) {
return x
} }
return decodeURIComponent(x.replace(/\+/g, ' '));
}; };
/** /**
* small helper function to urlencode strings * highlight a given string on a node by wrapping it in
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name. * span elements with the given class name.
*/ */
jQuery.fn.highlightText = function(text, className) { const _highlight = (node, addItems, text, className) => {
function highlight(node, addItems) { if (node.nodeType === Node.TEXT_NODE) {
if (node.nodeType === 3) { const val = node.nodeValue;
var val = node.nodeValue; const parent = node.parentNode;
var pos = val.toLowerCase().indexOf(text); const pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && if (
!jQuery(node.parentNode).hasClass(className) && pos >= 0 &&
!jQuery(node.parentNode).hasClass("nohighlight")) { !parent.classList.contains(className) &&
var span; !parent.classList.contains("nohighlight")
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); ) {
if (isInSVG) { let span;
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else { const closestNode = parent.closest("body, svg, foreignObject");
span = document.createElement("span"); const isInSVG = closestNode && closestNode.matches("svg");
span.className = className; if (isInSVG) {
} span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
span.appendChild(document.createTextNode(val.substr(pos, text.length))); } else {
node.parentNode.insertBefore(span, node.parentNode.insertBefore( span = document.createElement("span");
span.classList.add(className);
}
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
parent.insertBefore(
span,
parent.insertBefore(
document.createTextNode(val.substr(pos + text.length)), document.createTextNode(val.substr(pos + text.length)),
node.nextSibling)); node.nextSibling
node.nodeValue = val.substr(0, pos); )
if (isInSVG) { );
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); node.nodeValue = val.substr(0, pos);
var bbox = node.parentElement.getBBox();
rect.x.baseVal.value = bbox.x; if (isInSVG) {
rect.y.baseVal.value = bbox.y; const rect = document.createElementNS(
rect.width.baseVal.value = bbox.width; "http://www.w3.org/2000/svg",
rect.height.baseVal.value = bbox.height; "rect"
rect.setAttribute('class', className); );
addItems.push({ const bbox = parent.getBBox();
"parent": node.parentNode, rect.x.baseVal.value = bbox.x;
"target": rect}); rect.y.baseVal.value = bbox.y;
} rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute("class", className);
addItems.push({ parent: parent, target: rect });
} }
} }
else if (!jQuery(node).is("button, select, textarea")) { } else if (node.matches && !node.matches("button, select, textarea")) {
jQuery.each(node.childNodes, function() { node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
highlight(this, addItems);
});
}
} }
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
}; };
const _highlightText = (thisNode, text, className) => {
/* let addItems = [];
* backward compatibility for jQuery.browser _highlight(thisNode, addItems, text, className);
* This will be supported until firefox bug is fixed. addItems.forEach((obj) =>
*/ obj.parent.insertAdjacentElement("beforebegin", obj.target)
if (!jQuery.browser) { );
jQuery.uaMatch = function(ua) { };
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
/** /**
* Small JavaScript module for the documentation. * Small JavaScript module for the documentation.
*/ */
var Documentation = { const Documentation = {
init: () => {
init : function() { Documentation.highlightSearchWords();
this.fixFirefoxAnchorBug(); Documentation.initDomainIndexTable();
this.highlightSearchWords(); Documentation.initOnKeyListeners();
this.initIndexTable();
if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
this.initOnKeyListeners();
}
}, },
/** /**
* i18n support * i18n support
*/ */
TRANSLATIONS : {}, TRANSLATIONS: {},
PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
LOCALE : 'unknown', LOCALE: "unknown",
// gettext and ngettext don't access this so that the functions // gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext) // can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) { gettext: (string) => {
var translated = Documentation.TRANSLATIONS[string]; const translated = Documentation.TRANSLATIONS[string];
if (typeof translated === 'undefined') switch (typeof translated) {
return string; case "undefined":
return (typeof translated === 'string') ? translated : translated[0]; return string; // no translation
case "string":
return translated; // translation exists
default:
return translated[0]; // (singular, plural) translation tuple exists
}
}, },
ngettext : function(singular, plural, n) { ngettext: (singular, plural, n) => {
var translated = Documentation.TRANSLATIONS[singular]; const translated = Documentation.TRANSLATIONS[singular];
if (typeof translated === 'undefined') if (typeof translated !== "undefined")
return (n == 1) ? singular : plural; return translated[Documentation.PLURAL_EXPR(n)];
return translated[Documentation.PLURALEXPR(n)]; return n === 1 ? singular : plural;
}, },
addTranslations : function(catalog) { addTranslations: (catalog) => {
for (var key in catalog.messages) Object.assign(Documentation.TRANSLATIONS, catalog.messages);
this.TRANSLATIONS[key] = catalog.messages[key]; Documentation.PLURAL_EXPR = new Function(
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); "n",
this.LOCALE = catalog.locale; `return (${catalog.plural_expr})`
}, );
Documentation.LOCALE = catalog.locale;
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
}, },
/** /**
* highlight the search words provided in the url in the text * highlight the search words provided in the url in the text
*/ */
highlightSearchWords : function() { highlightSearchWords: () => {
var params = $.getQueryParameters(); const highlight =
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; new URLSearchParams(window.location.search).get("highlight") || "";
if (terms.length) { const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
var body = $('div.body'); if (terms.length === 0) return; // nothing to do
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/** // There should never be more than one element matching "div.body"
* init the domain index toggle buttons const divBody = document.querySelectorAll("div.body");
*/ const body = divBody.length ? divBody[0] : document.querySelector("body");
initIndexTable : function() { window.setTimeout(() => {
var togglers = $('img.toggler').click(function() { terms.forEach((term) => _highlightText(body, term, "highlighted"));
var src = $(this).attr('src'); }, 10);
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle(); const searchBox = document.getElementById("searchbox");
if (src.substr(-9) === 'minus.png') if (searchBox === null) return;
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); searchBox.appendChild(
else document
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); .createRange()
}).css('display', ''); .createContextualFragment(
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { '<p class="highlight-link">' +
togglers.click(); '<a href="javascript:Documentation.hideSearchWords()">' +
} Documentation.gettext("Hide Search Matches") +
"</a></p>"
)
);
}, },
/** /**
* helper function to hide the search marks again * helper function to hide the search marks again
*/ */
hideSearchWords : function() { hideSearchWords: () => {
$('#searchbox .highlight-link').fadeOut(300); document
$('span.highlighted').removeClass('highlighted'); .querySelectorAll("#searchbox .highlight-link")
var url = new URL(window.location); .forEach((el) => el.remove());
url.searchParams.delete('highlight'); document
window.history.replaceState({}, '', url); .querySelectorAll("span.highlighted")
.forEach((el) => el.classList.remove("highlighted"));
const url = new URL(window.location);
url.searchParams.delete("highlight");
window.history.replaceState({}, "", url);
}, },
/** /**
* make the url absolute * helper function to focus on search bar
*/ */
makeURL : function(relativeURL) { focusSearchBar: () => {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; document.querySelectorAll("input[name=q]")[0]?.focus();
}, },
/** /**
* get the current relative url * Initialise the domain index toggle buttons
*/ */
getCurrentURL : function() { initDomainIndexTable: () => {
var path = document.location.pathname; const toggler = (el) => {
var parts = path.split(/\//); const idNumber = el.id.substr(7);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
if (this === '..') if (el.src.substr(-9) === "minus.png") {
parts.pop(); el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
}); toggledRows.forEach((el) => (el.style.display = "none"));
var url = parts.join('/'); } else {
return path.substring(url.lastIndexOf('/') + 1, path.length - 1); el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
toggledRows.forEach((el) => (el.style.display = ""));
}
};
const togglerElements = document.querySelectorAll("img.toggler");
togglerElements.forEach((el) =>
el.addEventListener("click", (event) => toggler(event.currentTarget))
);
togglerElements.forEach((el) => (el.style.display = ""));
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
}, },
initOnKeyListeners: function() { initOnKeyListeners: () => {
$(document).keydown(function(event) { // only install a listener if it is really needed
var activeElementType = document.activeElement.tagName; if (
// don't navigate when in search box, textarea, dropdown or button !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
&& activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey )
&& !event.shiftKey) { return;
switch (event.keyCode) {
case 37: // left const blacklistedElements = new Set([
var prevHref = $('link[rel="prev"]').prop('href'); "TEXTAREA",
if (prevHref) { "INPUT",
window.location.href = prevHref; "SELECT",
return false; "BUTTON",
]);
document.addEventListener("keydown", (event) => {
if (blacklistedElements.has(document.activeElement.tagName)) return; // bail for input elements
if (event.altKey || event.ctrlKey || event.metaKey) return; // bail with special keys
if (!event.shiftKey) {
switch (event.key) {
case "ArrowLeft":
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
const prevLink = document.querySelector('link[rel="prev"]');
if (prevLink && prevLink.href) {
window.location.href = prevLink.href;
event.preventDefault();
} }
break; break;
case 39: // right case "ArrowRight":
var nextHref = $('link[rel="next"]').prop('href'); if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
if (nextHref) {
window.location.href = nextHref; const nextLink = document.querySelector('link[rel="next"]');
return false; if (nextLink && nextLink.href) {
window.location.href = nextLink.href;
event.preventDefault();
} }
break; break;
case "Escape":
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
Documentation.hideSearchWords();
event.preventDefault();
} }
} }
// some keyboard layouts may need Shift to get /
switch (event.key) {
case "/":
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
Documentation.focusSearchBar();
event.preventDefault();
}
}); });
} },
}; };
// quick alias for translations // quick alias for translations
_ = Documentation.gettext; const _ = Documentation.gettext;
$(document).ready(function() { _ready(Documentation.init);
Documentation.init();
});

View File

@ -1,12 +1,14 @@
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.5.7', VERSION: '0.6.10',
LANGUAGE: 'None', LANGUAGE: 'en',
COLLAPSE_INDEX: false, COLLAPSE_INDEX: false,
BUILDER: 'html', BUILDER: 'html',
FILE_SUFFIX: '.html', FILE_SUFFIX: '.html',
LINK_SUFFIX: '.html', LINK_SUFFIX: '.html',
HAS_SOURCE: true, HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt', SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false NAVIGATION_WITH_KEYS: false,
SHOW_SEARCH_SUMMARY: true,
ENABLE_SEARCH_SHORTCUTS: false,
}; };

View File

@ -1,15 +1,15 @@
/*! /*!
* jQuery JavaScript Library v3.5.1 * jQuery JavaScript Library v3.6.0
* https://jquery.com/ * https://jquery.com/
* *
* Includes Sizzle.js * Includes Sizzle.js
* https://sizzlejs.com/ * https://sizzlejs.com/
* *
* Copyright JS Foundation and other contributors * Copyright OpenJS Foundation and other contributors
* Released under the MIT license * Released under the MIT license
* https://jquery.org/license * https://jquery.org/license
* *
* Date: 2020-05-04T22:49Z * Date: 2021-03-02T17:08Z
*/ */
( function( global, factory ) { ( function( global, factory ) {
@ -76,12 +76,16 @@ var support = {};
var isFunction = function isFunction( obj ) { var isFunction = function isFunction( obj ) {
// Support: Chrome <=57, Firefox <=52 // Support: Chrome <=57, Firefox <=52
// In some browsers, typeof returns "function" for HTML <object> elements // In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`). // (i.e., `typeof document.createElement( "object" ) === "function"`).
// We don't want to classify *any* DOM node as a function. // We don't want to classify *any* DOM node as a function.
return typeof obj === "function" && typeof obj.nodeType !== "number"; // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5
}; // Plus for old WebKit, typeof returns "function" for HTML collections
// (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756)
return typeof obj === "function" && typeof obj.nodeType !== "number" &&
typeof obj.item !== "function";
};
var isWindow = function isWindow( obj ) { var isWindow = function isWindow( obj ) {
@ -147,7 +151,7 @@ function toType( obj ) {
var var
version = "3.5.1", version = "3.6.0",
// Define a local copy of jQuery // Define a local copy of jQuery
jQuery = function( selector, context ) { jQuery = function( selector, context ) {
@ -401,7 +405,7 @@ jQuery.extend( {
if ( isArrayLike( Object( arr ) ) ) { if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret, jQuery.merge( ret,
typeof arr === "string" ? typeof arr === "string" ?
[ arr ] : arr [ arr ] : arr
); );
} else { } else {
push.call( ret, arr ); push.call( ret, arr );
@ -496,9 +500,9 @@ if ( typeof Symbol === "function" ) {
// Populate the class2type map // Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( _i, name ) { function( _i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase(); class2type[ "[object " + name + "]" ] = name.toLowerCase();
} ); } );
function isArrayLike( obj ) { function isArrayLike( obj ) {
@ -518,14 +522,14 @@ function isArrayLike( obj ) {
} }
var Sizzle = var Sizzle =
/*! /*!
* Sizzle CSS Selector Engine v2.3.5 * Sizzle CSS Selector Engine v2.3.6
* https://sizzlejs.com/ * https://sizzlejs.com/
* *
* Copyright JS Foundation and other contributors * Copyright JS Foundation and other contributors
* Released under the MIT license * Released under the MIT license
* https://js.foundation/ * https://js.foundation/
* *
* Date: 2020-03-14 * Date: 2021-02-16
*/ */
( function( window ) { ( function( window ) {
var i, var i,
@ -1108,8 +1112,8 @@ support = Sizzle.support = {};
* @returns {Boolean} True iff elem is a non-HTML XML node * @returns {Boolean} True iff elem is a non-HTML XML node
*/ */
isXML = Sizzle.isXML = function( elem ) { isXML = Sizzle.isXML = function( elem ) {
var namespace = elem.namespaceURI, var namespace = elem && elem.namespaceURI,
docElem = ( elem.ownerDocument || elem ).documentElement; docElem = elem && ( elem.ownerDocument || elem ).documentElement;
// Support: IE <=8 // Support: IE <=8
// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
@ -3024,9 +3028,9 @@ var rneedsContext = jQuery.expr.match.needsContext;
function nodeName( elem, name ) { function nodeName( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
}; }
var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
@ -3997,8 +4001,8 @@ jQuery.extend( {
resolveContexts = Array( i ), resolveContexts = Array( i ),
resolveValues = slice.call( arguments ), resolveValues = slice.call( arguments ),
// the master Deferred // the primary Deferred
master = jQuery.Deferred(), primary = jQuery.Deferred(),
// subordinate callback factory // subordinate callback factory
updateFunc = function( i ) { updateFunc = function( i ) {
@ -4006,30 +4010,30 @@ jQuery.extend( {
resolveContexts[ i ] = this; resolveContexts[ i ] = this;
resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
if ( !( --remaining ) ) { if ( !( --remaining ) ) {
master.resolveWith( resolveContexts, resolveValues ); primary.resolveWith( resolveContexts, resolveValues );
} }
}; };
}; };
// Single- and empty arguments are adopted like Promise.resolve // Single- and empty arguments are adopted like Promise.resolve
if ( remaining <= 1 ) { if ( remaining <= 1 ) {
adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,
!remaining ); !remaining );
// Use .then() to unwrap secondary thenables (cf. gh-3000) // Use .then() to unwrap secondary thenables (cf. gh-3000)
if ( master.state() === "pending" || if ( primary.state() === "pending" ||
isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
return master.then(); return primary.then();
} }
} }
// Multiple arguments are aggregated like Promise.all array elements // Multiple arguments are aggregated like Promise.all array elements
while ( i-- ) { while ( i-- ) {
adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );
} }
return master.promise(); return primary.promise();
} }
} ); } );
@ -4180,8 +4184,8 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
for ( ; i < len; i++ ) { for ( ; i < len; i++ ) {
fn( fn(
elems[ i ], key, raw ? elems[ i ], key, raw ?
value : value :
value.call( elems[ i ], i, fn( elems[ i ], key ) ) value.call( elems[ i ], i, fn( elems[ i ], key ) )
); );
} }
} }
@ -5089,10 +5093,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) {
} }
var var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
function returnTrue() { function returnTrue() {
return true; return true;
@ -5387,8 +5388,8 @@ jQuery.event = {
event = jQuery.event.fix( nativeEvent ), event = jQuery.event.fix( nativeEvent ),
handlers = ( handlers = (
dataPriv.get( this, "events" ) || Object.create( null ) dataPriv.get( this, "events" ) || Object.create( null )
)[ event.type ] || [], )[ event.type ] || [],
special = jQuery.event.special[ event.type ] || {}; special = jQuery.event.special[ event.type ] || {};
// Use the fix-ed jQuery.Event rather than the (read-only) native event // Use the fix-ed jQuery.Event rather than the (read-only) native event
@ -5512,12 +5513,12 @@ jQuery.event = {
get: isFunction( hook ) ? get: isFunction( hook ) ?
function() { function() {
if ( this.originalEvent ) { if ( this.originalEvent ) {
return hook( this.originalEvent ); return hook( this.originalEvent );
} }
} : } :
function() { function() {
if ( this.originalEvent ) { if ( this.originalEvent ) {
return this.originalEvent[ name ]; return this.originalEvent[ name ];
} }
}, },
@ -5656,7 +5657,13 @@ function leverageNative( el, type, expectSync ) {
// Cancel the outer synthetic event // Cancel the outer synthetic event
event.stopImmediatePropagation(); event.stopImmediatePropagation();
event.preventDefault(); event.preventDefault();
return result.value;
// Support: Chrome 86+
// In Chrome, if an element having a focusout handler is blurred by
// clicking outside of it, it invokes the handler synchronously. If
// that handler calls `.remove()` on the element, the data is cleared,
// leaving `result` undefined. We need to guard against this.
return result && result.value;
} }
// If this is an inner synthetic event for an event with a bubbling surrogate // If this is an inner synthetic event for an event with a bubbling surrogate
@ -5821,34 +5828,7 @@ jQuery.each( {
targetTouches: true, targetTouches: true,
toElement: true, toElement: true,
touches: true, touches: true,
which: true
which: function( event ) {
var button = event.button;
// Add which for key events
if ( event.which == null && rkeyEvent.test( event.type ) ) {
return event.charCode != null ? event.charCode : event.keyCode;
}
// Add which for click: 1 === left; 2 === middle; 3 === right
if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
if ( button & 1 ) {
return 1;
}
if ( button & 2 ) {
return 3;
}
if ( button & 4 ) {
return 2;
}
return 0;
}
return event.which;
}
}, jQuery.event.addProp ); }, jQuery.event.addProp );
jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
@ -5874,6 +5854,12 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
return true; return true;
}, },
// Suppress native focus or blur as it's already being fired
// in leverageNative.
_default: function() {
return true;
},
delegateType: delegateType delegateType: delegateType
}; };
} ); } );
@ -6541,6 +6527,10 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
// set in CSS while `offset*` properties report correct values. // set in CSS while `offset*` properties report correct values.
// Behavior in IE 9 is more subtle than in newer versions & it passes // Behavior in IE 9 is more subtle than in newer versions & it passes
// some versions of this test; make sure not to make it pass there! // some versions of this test; make sure not to make it pass there!
//
// Support: Firefox 70+
// Only Firefox includes border widths
// in computed dimensions. (gh-4529)
reliableTrDimensions: function() { reliableTrDimensions: function() {
var table, tr, trChild, trStyle; var table, tr, trChild, trStyle;
if ( reliableTrDimensionsVal == null ) { if ( reliableTrDimensionsVal == null ) {
@ -6548,17 +6538,32 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
tr = document.createElement( "tr" ); tr = document.createElement( "tr" );
trChild = document.createElement( "div" ); trChild = document.createElement( "div" );
table.style.cssText = "position:absolute;left:-11111px"; table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate";
tr.style.cssText = "border:1px solid";
// Support: Chrome 86+
// Height set through cssText does not get applied.
// Computed height then comes back as 0.
tr.style.height = "1px"; tr.style.height = "1px";
trChild.style.height = "9px"; trChild.style.height = "9px";
// Support: Android 8 Chrome 86+
// In our bodyBackground.html iframe,
// display for all div elements is set to "inline",
// which causes a problem only in Android 8 Chrome 86.
// Ensuring the div is display: block
// gets around this issue.
trChild.style.display = "block";
documentElement documentElement
.appendChild( table ) .appendChild( table )
.appendChild( tr ) .appendChild( tr )
.appendChild( trChild ); .appendChild( trChild );
trStyle = window.getComputedStyle( tr ); trStyle = window.getComputedStyle( tr );
reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) +
parseInt( trStyle.borderTopWidth, 10 ) +
parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight;
documentElement.removeChild( table ); documentElement.removeChild( table );
} }
@ -7022,10 +7027,10 @@ jQuery.each( [ "height", "width" ], function( _i, dimension ) {
// Running getBoundingClientRect on a disconnected node // Running getBoundingClientRect on a disconnected node
// in IE throws an error. // in IE throws an error.
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
swap( elem, cssShow, function() { swap( elem, cssShow, function() {
return getWidthOrHeight( elem, dimension, extra ); return getWidthOrHeight( elem, dimension, extra );
} ) : } ) :
getWidthOrHeight( elem, dimension, extra ); getWidthOrHeight( elem, dimension, extra );
} }
}, },
@ -7084,7 +7089,7 @@ jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
swap( elem, { marginLeft: 0 }, function() { swap( elem, { marginLeft: 0 }, function() {
return elem.getBoundingClientRect().left; return elem.getBoundingClientRect().left;
} ) } )
) + "px"; ) + "px";
} }
} }
); );
@ -7223,7 +7228,7 @@ Tween.propHooks = {
if ( jQuery.fx.step[ tween.prop ] ) { if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween ); jQuery.fx.step[ tween.prop ]( tween );
} else if ( tween.elem.nodeType === 1 && ( } else if ( tween.elem.nodeType === 1 && (
jQuery.cssHooks[ tween.prop ] || jQuery.cssHooks[ tween.prop ] ||
tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
} else { } else {
@ -7468,7 +7473,7 @@ function defaultPrefilter( elem, props, opts ) {
anim.done( function() { anim.done( function() {
/* eslint-enable no-loop-func */ /* eslint-enable no-loop-func */
// The final step of a "hide" animation is actually hiding the element // The final step of a "hide" animation is actually hiding the element
if ( !hidden ) { if ( !hidden ) {
@ -7588,7 +7593,7 @@ function Animation( elem, properties, options ) {
tweens: [], tweens: [],
createTween: function( prop, end ) { createTween: function( prop, end ) {
var tween = jQuery.Tween( elem, animation.opts, prop, end, var tween = jQuery.Tween( elem, animation.opts, prop, end,
animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.opts.specialEasing[ prop ] || animation.opts.easing );
animation.tweens.push( tween ); animation.tweens.push( tween );
return tween; return tween;
}, },
@ -7761,7 +7766,8 @@ jQuery.fn.extend( {
anim.stop( true ); anim.stop( true );
} }
}; };
doAnimation.finish = doAnimation;
doAnimation.finish = doAnimation;
return empty || optall.queue === false ? return empty || optall.queue === false ?
this.each( doAnimation ) : this.each( doAnimation ) :
@ -8401,8 +8407,8 @@ jQuery.fn.extend( {
if ( this.setAttribute ) { if ( this.setAttribute ) {
this.setAttribute( "class", this.setAttribute( "class",
className || value === false ? className || value === false ?
"" : "" :
dataPriv.get( this, "__className__" ) || "" dataPriv.get( this, "__className__" ) || ""
); );
} }
} }
@ -8417,7 +8423,7 @@ jQuery.fn.extend( {
while ( ( elem = this[ i++ ] ) ) { while ( ( elem = this[ i++ ] ) ) {
if ( elem.nodeType === 1 && if ( elem.nodeType === 1 &&
( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
return true; return true;
} }
} }
@ -8707,9 +8713,7 @@ jQuery.extend( jQuery.event, {
special.bindType || type; special.bindType || type;
// jQuery handler // jQuery handler
handle = ( handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] &&
dataPriv.get( cur, "events" ) || Object.create( null )
)[ event.type ] &&
dataPriv.get( cur, "handle" ); dataPriv.get( cur, "handle" );
if ( handle ) { if ( handle ) {
handle.apply( cur, data ); handle.apply( cur, data );
@ -8856,7 +8860,7 @@ var rquery = ( /\?/ );
// Cross-browser xml parsing // Cross-browser xml parsing
jQuery.parseXML = function( data ) { jQuery.parseXML = function( data ) {
var xml; var xml, parserErrorElem;
if ( !data || typeof data !== "string" ) { if ( !data || typeof data !== "string" ) {
return null; return null;
} }
@ -8865,12 +8869,17 @@ jQuery.parseXML = function( data ) {
// IE throws on parseFromString with invalid input. // IE throws on parseFromString with invalid input.
try { try {
xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
} catch ( e ) { } catch ( e ) {}
xml = undefined;
}
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ];
jQuery.error( "Invalid XML: " + data ); if ( !xml || parserErrorElem ) {
jQuery.error( "Invalid XML: " + (
parserErrorElem ?
jQuery.map( parserErrorElem.childNodes, function( el ) {
return el.textContent;
} ).join( "\n" ) :
data
) );
} }
return xml; return xml;
}; };
@ -8971,16 +8980,14 @@ jQuery.fn.extend( {
// Can add propHook for "elements" to filter or add form elements // Can add propHook for "elements" to filter or add form elements
var elements = jQuery.prop( this, "elements" ); var elements = jQuery.prop( this, "elements" );
return elements ? jQuery.makeArray( elements ) : this; return elements ? jQuery.makeArray( elements ) : this;
} ) } ).filter( function() {
.filter( function() {
var type = this.type; var type = this.type;
// Use .is( ":disabled" ) so that fieldset[disabled] works // Use .is( ":disabled" ) so that fieldset[disabled] works
return this.name && !jQuery( this ).is( ":disabled" ) && return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) ); ( this.checked || !rcheckableType.test( type ) );
} ) } ).map( function( _i, elem ) {
.map( function( _i, elem ) {
var val = jQuery( this ).val(); var val = jQuery( this ).val();
if ( val == null ) { if ( val == null ) {
@ -9033,7 +9040,8 @@ var
// Anchor tag for parsing the document origin // Anchor tag for parsing the document origin
originAnchor = document.createElement( "a" ); originAnchor = document.createElement( "a" );
originAnchor.href = location.href;
originAnchor.href = location.href;
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) { function addToPrefiltersOrTransports( structure ) {
@ -9414,8 +9422,8 @@ jQuery.extend( {
// Context for global events is callbackContext if it is a DOM node or jQuery collection // Context for global events is callbackContext if it is a DOM node or jQuery collection
globalEventContext = s.context && globalEventContext = s.context &&
( callbackContext.nodeType || callbackContext.jquery ) ? ( callbackContext.nodeType || callbackContext.jquery ) ?
jQuery( callbackContext ) : jQuery( callbackContext ) :
jQuery.event, jQuery.event,
// Deferreds // Deferreds
deferred = jQuery.Deferred(), deferred = jQuery.Deferred(),
@ -9727,8 +9735,10 @@ jQuery.extend( {
response = ajaxHandleResponses( s, jqXHR, responses ); response = ajaxHandleResponses( s, jqXHR, responses );
} }
// Use a noop converter for missing script // Use a noop converter for missing script but not if jsonp
if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { if ( !isSuccess &&
jQuery.inArray( "script", s.dataTypes ) > -1 &&
jQuery.inArray( "json", s.dataTypes ) < 0 ) {
s.converters[ "text script" ] = function() {}; s.converters[ "text script" ] = function() {};
} }
@ -10466,12 +10476,6 @@ jQuery.offset = {
options.using.call( elem, props ); options.using.call( elem, props );
} else { } else {
if ( typeof props.top === "number" ) {
props.top += "px";
}
if ( typeof props.left === "number" ) {
props.left += "px";
}
curElem.css( props ); curElem.css( props );
} }
} }
@ -10640,8 +10644,11 @@ jQuery.each( [ "top", "left" ], function( _i, prop ) {
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, jQuery.each( {
function( defaultExtra, funcName ) { padding: "inner" + name,
content: type,
"": "outer" + name
}, function( defaultExtra, funcName ) {
// Margin is only for outerHeight, outerWidth // Margin is only for outerHeight, outerWidth
jQuery.fn[ funcName ] = function( margin, value ) { jQuery.fn[ funcName ] = function( margin, value ) {
@ -10726,7 +10733,8 @@ jQuery.fn.extend( {
} }
} ); } );
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + jQuery.each(
( "blur focus focusin focusout resize scroll click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup contextmenu" ).split( " " ), "change select submit keydown keypress keyup contextmenu" ).split( " " ),
function( _i, name ) { function( _i, name ) {
@ -10737,7 +10745,8 @@ jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
this.on( name, null, data, fn ) : this.on( name, null, data, fn ) :
this.trigger( name ); this.trigger( name );
}; };
} ); }
);

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,7 @@
* *
*/ */
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"]; var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"];
/* Non-minified version is copied as a separate JS file, is available */ /* Non-minified version is copied as a separate JS file, is available */
@ -197,101 +197,3 @@ var Stemmer = function() {
} }
} }
var splitChars = (function() {
var result = {};
var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
var i, j, start, end;
for (i = 0; i < singles.length; i++) {
result[singles[i]] = true;
}
var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
[722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
[1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
[1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
[1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
[2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
[2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
[2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
[2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
[2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
[2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
[2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
[3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
[3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
[3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
[3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
[3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
[3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
[4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
[4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
[4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
[4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
[5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
[6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
[6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
[6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
[6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
[7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
[7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
[8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
[8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
[8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
[10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
[11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
[12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
[12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
[12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
[19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
[42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
[42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
[43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
[43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
[43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
[43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
[44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
[57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
[64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
[65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
[65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
for (i = 0; i < ranges.length; i++) {
start = ranges[i][0];
end = ranges[i][1];
for (j = start; j <= end; j++) {
result[j] = true;
}
}
return result;
})();
function splitQuery(query) {
var result = [];
var start = -1;
for (var i = 0; i < query.length; i++) {
if (splitChars[query.charCodeAt(i)]) {
if (start !== -1) {
result.push(query.slice(start, i));
start = -1;
}
} else if (start === -1) {
start = i;
}
}
if (start !== -1) {
result.push(query.slice(start));
}
return result;
}

View File

@ -8,18 +8,20 @@
* :license: BSD, see LICENSE for details. * :license: BSD, see LICENSE for details.
* *
*/ */
"use strict";
if (!Scorer) { /**
/** * Simple result scoring code.
* Simple result scoring code. */
*/ if (typeof Scorer === "undefined") {
var Scorer = { var Scorer = {
// Implement the following function to further tweak the score for each result // Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score] // The function takes a result array [docname, title, anchor, descr, score, filename]
// and returns the new score. // and returns the new score.
/* /*
score: function(result) { score: result => {
return result[4]; const [docname, title, anchor, descr, score, filename] = result
return score
}, },
*/ */
@ -28,9 +30,11 @@ if (!Scorer) {
// or matches in the last dotted part of the object name // or matches in the last dotted part of the object name
objPartialMatch: 6, objPartialMatch: 6,
// Additive scores depending on the priority of the object // Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults objPrio: {
1: 5, // used to be objectResults 0: 15, // used to be importantResults
2: -5}, // used to be unimportantResults 1: 5, // used to be objectResults
2: -5, // used to be unimportantResults
},
// Used when the priority is not in the mapping. // Used when the priority is not in the mapping.
objPrioDefault: 0, objPrioDefault: 0,
@ -39,456 +43,455 @@ if (!Scorer) {
partialTitle: 7, partialTitle: 7,
// query found in terms // query found in terms
term: 5, term: 5,
partialTerm: 2 partialTerm: 2,
}; };
} }
if (!splitQuery) { const _removeChildren = (element) => {
function splitQuery(query) { while (element && element.lastChild) element.removeChild(element.lastChild);
return query.split(/\s+/); };
/**
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
*/
const _escapeRegExp = (string) =>
string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
const _displayItem = (item, highlightTerms, searchTerms) => {
const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT;
const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX;
const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;
const [docName, title, anchor, descr] = item;
let listItem = document.createElement("li");
let requestUrl;
let linkUrl;
if (docBuilder === "dirhtml") {
// dirhtml builder
let dirname = docName + "/";
if (dirname.match(/\/index\/$/))
dirname = dirname.substring(0, dirname.length - 6);
else if (dirname === "index/") dirname = "";
requestUrl = docUrlRoot + dirname;
linkUrl = requestUrl;
} else {
// normal html builders
requestUrl = docUrlRoot + docName + docFileSuffix;
linkUrl = docName + docLinkSuffix;
} }
const params = new URLSearchParams();
params.set("highlight", [...highlightTerms].join(" "));
let linkEl = listItem.appendChild(document.createElement("a"));
linkEl.href = linkUrl + "?" + params.toString() + anchor;
linkEl.innerHTML = title;
if (descr)
listItem.appendChild(document.createElement("span")).innerText =
" (" + descr + ")";
else if (showSearchSummary)
fetch(requestUrl)
.then((responseData) => responseData.text())
.then((data) => {
if (data)
listItem.appendChild(
Search.makeSearchSummary(data, searchTerms, highlightTerms)
);
});
Search.output.appendChild(listItem);
};
const _finishSearch = (resultCount) => {
Search.stopPulse();
Search.title.innerText = _("Search Results");
if (!resultCount)
Search.status.innerText = Documentation.gettext(
"Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories."
);
else
Search.status.innerText = _(
`Search finished, found ${resultCount} page(s) matching the search query.`
);
};
const _displayNextItem = (
results,
resultCount,
highlightTerms,
searchTerms
) => {
// results left, load the summary and display it
// this is intended to be dynamic (don't sub resultsCount)
if (results.length) {
_displayItem(results.pop(), highlightTerms, searchTerms);
setTimeout(
() => _displayNextItem(results, resultCount, highlightTerms, searchTerms),
5
);
}
// search finished, update title and status message
else _finishSearch(resultCount);
};
/**
* Default splitQuery function. Can be overridden in ``sphinx.search`` with a
* custom function per language.
*
* The regular expression works by splitting the string on consecutive characters
* that are not Unicode letters, numbers, underscores, or emoji characters.
* This is the same as ``\W+`` in Python, preserving the surrogate pair area.
*/
if (typeof splitQuery === "undefined") {
var splitQuery = (query) => query
.split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu)
.filter(term => term) // remove remaining empty strings
} }
/** /**
* Search Module * Search Module
*/ */
var Search = { const Search = {
_index: null,
_queued_query: null,
_pulse_status: -1,
_index : null, htmlToText: (htmlString) => {
_queued_query : null, const htmlElement = document
_pulse_status : -1, .createRange()
.createContextualFragment(htmlString);
htmlToText : function(htmlString) { _removeChildren(htmlElement.querySelectorAll(".headerlink"));
var virtualDocument = document.implementation.createHTMLDocument('virtual'); const docContent = htmlElement.querySelector('[role="main"]');
var htmlElement = $(htmlString, virtualDocument); if (docContent !== undefined) return docContent.textContent;
htmlElement.find('.headerlink').remove(); console.warn(
docContent = htmlElement.find('[role=main]')[0]; "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."
if(docContent === undefined) { );
console.warn("Content block not found. Sphinx search tries to obtain it " + return "";
"via '[role=main]'. Could you check your theme or template.");
return "";
}
return docContent.textContent || docContent.innerText;
}, },
init : function() { init: () => {
var params = $.getQueryParameters(); const query = new URLSearchParams(window.location.search).get("q");
if (params.q) { document
var query = params.q[0]; .querySelectorAll('input[name="q"]')
$('input[name="q"]')[0].value = query; .forEach((el) => (el.value = query));
this.performSearch(query); if (query) Search.performSearch(query);
}
}, },
loadIndex : function(url) { loadIndex: (url) =>
$.ajax({type: "GET", url: url, data: null, (document.body.appendChild(document.createElement("script")).src = url),
dataType: "script", cache: true,
complete: function(jqxhr, textstatus) {
if (textstatus != "success") {
document.getElementById("searchindexloader").src = url;
}
}});
},
setIndex : function(index) { setIndex: (index) => {
var q; Search._index = index;
this._index = index; if (Search._queued_query !== null) {
if ((q = this._queued_query) !== null) { const query = Search._queued_query;
this._queued_query = null; Search._queued_query = null;
Search.query(q); Search.query(query);
} }
}, },
hasIndex : function() { hasIndex: () => Search._index !== null,
return this._index !== null;
},
deferQuery : function(query) { deferQuery: (query) => (Search._queued_query = query),
this._queued_query = query;
},
stopPulse : function() { stopPulse: () => (Search._pulse_status = -1),
this._pulse_status = 0;
},
startPulse : function() { startPulse: () => {
if (this._pulse_status >= 0) if (Search._pulse_status >= 0) return;
return;
function pulse() { const pulse = () => {
var i;
Search._pulse_status = (Search._pulse_status + 1) % 4; Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = ''; Search.dots.innerText = ".".repeat(Search._pulse_status);
for (i = 0; i < Search._pulse_status; i++) if (Search._pulse_status >= 0) window.setTimeout(pulse, 500);
dotString += '.'; };
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
}
pulse(); pulse();
}, },
/** /**
* perform a search for something (or wait until index is loaded) * perform a search for something (or wait until index is loaded)
*/ */
performSearch : function(query) { performSearch: (query) => {
// create the required interface elements // create the required interface elements
this.out = $('#search-results'); const searchText = document.createElement("h2");
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out); searchText.textContent = _("Searching");
this.dots = $('<span></span>').appendTo(this.title); const searchSummary = document.createElement("p");
this.status = $('<p class="search-summary">&nbsp;</p>').appendTo(this.out); searchSummary.classList.add("search-summary");
this.output = $('<ul class="search"/>').appendTo(this.out); searchSummary.innerText = "";
const searchList = document.createElement("ul");
searchList.classList.add("search");
$('#search-progress').text(_('Preparing search...')); const out = document.getElementById("search-results");
this.startPulse(); Search.title = out.appendChild(searchText);
Search.dots = Search.title.appendChild(document.createElement("span"));
Search.status = out.appendChild(searchSummary);
Search.output = out.appendChild(searchList);
const searchProgress = document.getElementById("search-progress");
// Some themes don't use the search progress node
if (searchProgress) {
searchProgress.innerText = _("Preparing search...");
}
Search.startPulse();
// index already loaded, the browser was quick! // index already loaded, the browser was quick!
if (this.hasIndex()) if (Search.hasIndex()) Search.query(query);
this.query(query); else Search.deferQuery(query);
else
this.deferQuery(query);
}, },
/** /**
* execute search (requires search index to be loaded) * execute search (requires search index to be loaded)
*/ */
query : function(query) { query: (query) => {
var i; // stem the search terms and add them to the correct list
const stemmer = new Stemmer();
const searchTerms = new Set();
const excludedTerms = new Set();
const highlightTerms = new Set();
const objectTerms = new Set(splitQuery(query.toLowerCase().trim()));
splitQuery(query.trim()).forEach((queryTerm) => {
const queryTermLower = queryTerm.toLowerCase();
// stem the searchterms and add them to the correct list // maybe skip this "word"
var stemmer = new Stemmer(); // stopwords array is from language_data.js
var searchterms = []; if (
var excluded = []; stopwords.indexOf(queryTermLower) !== -1 ||
var hlterms = []; queryTerm.match(/^\d+$/)
var tmp = splitQuery(query); )
var objectterms = []; return;
for (i = 0; i < tmp.length; i++) {
if (tmp[i] !== "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i] === "") {
// skip this "word"
continue;
}
// stem the word // stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase()); let word = stemmer.stemWord(queryTermLower);
// prevent stemmer from cutting word smaller than two chars
if(word.length < 3 && tmp[i].length >= 3) {
word = tmp[i];
}
var toAppend;
// select the correct list // select the correct list
if (word[0] == '-') { if (word[0] === "-") excludedTerms.add(word.substr(1));
toAppend = excluded;
word = word.substr(1);
}
else { else {
toAppend = searchterms; searchTerms.add(word);
hlterms.push(tmp[i].toLowerCase()); highlightTerms.add(queryTermLower);
} }
// only add if not already in the list });
if (!$u.contains(toAppend, word))
toAppend.push(word);
}
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:'); // console.debug("SEARCH: searching for:");
// console.info('required: ', searchterms); // console.info("required: ", [...searchTerms]);
// console.info('excluded: ', excluded); // console.info("excluded: ", [...excludedTerms]);
// prepare search // array of [docname, title, anchor, descr, score, filename]
var terms = this._index.terms; let results = [];
var titleterms = this._index.titleterms; _removeChildren(document.getElementById("search-progress"));
// array of [filename, title, anchor, descr, score]
var results = [];
$('#search-progress').empty();
// lookup as object // lookup as object
for (i = 0; i < objectterms.length; i++) { objectTerms.forEach((term) =>
var others = [].concat(objectterms.slice(0, i), results.push(...Search.performObjectSearch(term, objectTerms))
objectterms.slice(i+1, objectterms.length)); );
results = results.concat(this.performObjectSearch(objectterms[i], others));
}
// lookup as search terms in fulltext // lookup as search terms in fulltext
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms)); results.push(...Search.performTermsSearch(searchTerms, excludedTerms));
// let the scorer override scores with a custom scoring function // let the scorer override scores with a custom scoring function
if (Scorer.score) { if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item)));
for (i = 0; i < results.length; i++)
results[i][4] = Scorer.score(results[i]);
}
// now sort the results by score (in opposite order of appearance, since the // now sort the results by score (in opposite order of appearance, since the
// display function below uses pop() to retrieve items) and then // display function below uses pop() to retrieve items) and then
// alphabetically // alphabetically
results.sort(function(a, b) { results.sort((a, b) => {
var left = a[4]; const leftScore = a[4];
var right = b[4]; const rightScore = b[4];
if (left > right) { if (leftScore === rightScore) {
return 1;
} else if (left < right) {
return -1;
} else {
// same score: sort alphabetically // same score: sort alphabetically
left = a[1].toLowerCase(); const leftTitle = a[1].toLowerCase();
right = b[1].toLowerCase(); const rightTitle = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0); if (leftTitle === rightTitle) return 0;
return leftTitle > rightTitle ? -1 : 1; // inverted is intentional
} }
return leftScore > rightScore ? 1 : -1;
}); });
// remove duplicate search results
// note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept
let seen = new Set();
results = results.reverse().reduce((acc, result) => {
let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(',');
if (!seen.has(resultStr)) {
acc.push(result);
seen.add(resultStr);
}
return acc;
}, []);
results = results.reverse();
// for debugging // for debugging
//Search.lastresults = results.slice(); // a copy //Search.lastresults = results.slice(); // a copy
//console.info('search results:', Search.lastresults); // console.info("search results:", Search.lastresults);
// print the results // print the results
var resultCount = results.length; _displayNextItem(results, results.length, highlightTerms, searchTerms);
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li></li>');
var requestUrl = "";
var linkUrl = "";
if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + dirname;
linkUrl = requestUrl;
} else {
// normal html builders
requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX;
linkUrl = item[0] + DOCUMENTATION_OPTIONS.LINK_SUFFIX;
}
listItem.append($('<a/>').attr('href',
linkUrl +
highlightstring + item[2]).html(item[1]));
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
setTimeout(function() {
displayNextItem();
}, 5);
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.ajax({url: requestUrl,
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
if (data !== '' && data !== undefined) {
var summary = Search.makeSearchSummary(data, searchterms, hlterms);
if (summary) {
listItem.append(summary);
}
}
Search.output.append(listItem);
setTimeout(function() {
displayNextItem();
}, 5);
}});
} else {
// no source available, just display title
Search.output.append(listItem);
setTimeout(function() {
displayNextItem();
}, 5);
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
}, },
/** /**
* search for object names * search for object names
*/ */
performObjectSearch : function(object, otherterms) { performObjectSearch: (object, objectTerms) => {
var filenames = this._index.filenames; const filenames = Search._index.filenames;
var docnames = this._index.docnames; const docNames = Search._index.docnames;
var objects = this._index.objects; const objects = Search._index.objects;
var objnames = this._index.objnames; const objNames = Search._index.objnames;
var titles = this._index.titles; const titles = Search._index.titles;
var i; const results = [];
var results = [];
for (var prefix in objects) { const objectSearchCallback = (prefix, match) => {
for (var iMatch = 0; iMatch != objects[prefix].length; ++iMatch) { const name = match[4]
var match = objects[prefix][iMatch]; const fullname = (prefix ? prefix + "." : "") + name;
var name = match[4]; const fullnameLower = fullname.toLowerCase();
var fullname = (prefix ? prefix + '.' : '') + name; if (fullnameLower.indexOf(object) < 0) return;
var fullnameLower = fullname.toLowerCase()
if (fullnameLower.indexOf(object) > -1) {
var score = 0;
var parts = fullnameLower.split('.');
// check for different match types: exact matches of full name or
// "last name" (i.e. last dotted part)
if (fullnameLower == object || parts[parts.length - 1] == object) {
score += Scorer.objNameMatch;
// matches in last name
} else if (parts[parts.length - 1].indexOf(object) > -1) {
score += Scorer.objPartialMatch;
}
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
var anchor = match[3]; let score = 0;
if (anchor === '') const parts = fullnameLower.split(".");
anchor = fullname;
else if (anchor == '-') // check for different match types: exact matches of full name or
anchor = objnames[match[1]][1] + '-' + fullname; // "last name" (i.e. last dotted part)
// add custom score for some objects according to scorer if (fullnameLower === object || parts.slice(-1)[0] === object)
if (Scorer.objPrio.hasOwnProperty(match[2])) { score += Scorer.objNameMatch;
score += Scorer.objPrio[match[2]]; else if (parts.slice(-1)[0].indexOf(object) > -1)
} else { score += Scorer.objPartialMatch; // matches in last name
score += Scorer.objPrioDefault;
} const objName = objNames[match[1]][2];
results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]); const title = titles[match[0]];
}
// If more than one term searched for, we require other words to be
// found in the name/title/description
const otherTerms = new Set(objectTerms);
otherTerms.delete(object);
if (otherTerms.size > 0) {
const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase();
if (
[...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0)
)
return;
} }
}
let anchor = match[3];
if (anchor === "") anchor = fullname;
else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname;
const descr = objName + _(", in ") + title;
// add custom score for some objects according to scorer
if (Scorer.objPrio.hasOwnProperty(match[2]))
score += Scorer.objPrio[match[2]];
else score += Scorer.objPrioDefault;
results.push([
docNames[match[0]],
fullname,
"#" + anchor,
descr,
score,
filenames[match[0]],
]);
};
Object.keys(objects).forEach((prefix) =>
objects[prefix].forEach((array) =>
objectSearchCallback(prefix, array)
)
);
return results; return results;
}, },
/**
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
*/
escapeRegExp : function(string) {
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
},
/** /**
* search for full-text terms in the index * search for full-text terms in the index
*/ */
performTermsSearch : function(searchterms, excluded, terms, titleterms) { performTermsSearch: (searchTerms, excludedTerms) => {
var docnames = this._index.docnames; // prepare search
var filenames = this._index.filenames; const terms = Search._index.terms;
var titles = this._index.titles; const titleTerms = Search._index.titleterms;
const docNames = Search._index.docnames;
const filenames = Search._index.filenames;
const titles = Search._index.titles;
var i, j, file; const scoreMap = new Map();
var fileMap = {}; const fileMap = new Map();
var scoreMap = {};
var results = [];
// perform the search on the required terms // perform the search on the required terms
for (i = 0; i < searchterms.length; i++) { searchTerms.forEach((word) => {
var word = searchterms[i]; const files = [];
var files = []; const arr = [
var _o = [ { files: terms[word], score: Scorer.term },
{files: terms[word], score: Scorer.term}, { files: titleTerms[word], score: Scorer.title },
{files: titleterms[word], score: Scorer.title}
]; ];
// add support for partial matches // add support for partial matches
if (word.length > 2) { if (word.length > 2) {
var word_regex = this.escapeRegExp(word); const escapedWord = _escapeRegExp(word);
for (var w in terms) { Object.keys(terms).forEach((term) => {
if (w.match(word_regex) && !terms[word]) { if (term.match(escapedWord) && !terms[word])
_o.push({files: terms[w], score: Scorer.partialTerm}) arr.push({ files: terms[term], score: Scorer.partialTerm });
} });
} Object.keys(titleTerms).forEach((term) => {
for (var w in titleterms) { if (term.match(escapedWord) && !titleTerms[word])
if (w.match(word_regex) && !titleterms[word]) { arr.push({ files: titleTerms[word], score: Scorer.partialTitle });
_o.push({files: titleterms[w], score: Scorer.partialTitle}) });
}
}
} }
// no match but word was a required one // no match but word was a required one
if ($u.every(_o, function(o){return o.files === undefined;})) { if (arr.every((record) => record.files === undefined)) return;
break;
}
// found search word in contents // found search word in contents
$u.each(_o, function(o) { arr.forEach((record) => {
var _files = o.files; if (record.files === undefined) return;
if (_files === undefined)
return
if (_files.length === undefined) let recordFiles = record.files;
_files = [_files]; if (recordFiles.length === undefined) recordFiles = [recordFiles];
files = files.concat(_files); files.push(...recordFiles);
// set score for the word in each file to Scorer.term // set score for the word in each file
for (j = 0; j < _files.length; j++) { recordFiles.forEach((file) => {
file = _files[j]; if (!scoreMap.has(file)) scoreMap.set(file, {});
if (!(file in scoreMap)) scoreMap.get(file)[word] = record.score;
scoreMap[file] = {}; });
scoreMap[file][word] = o.score;
}
}); });
// create the mapping // create the mapping
for (j = 0; j < files.length; j++) { files.forEach((file) => {
file = files[j]; if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1)
if (file in fileMap && fileMap[file].indexOf(word) === -1) fileMap.get(file).push(word);
fileMap[file].push(word); else fileMap.set(file, [word]);
else });
fileMap[file] = [word]; });
}
}
// now check if the files don't contain excluded terms // now check if the files don't contain excluded terms
for (file in fileMap) { const results = [];
var valid = true; for (const [file, wordList] of fileMap) {
// check if all requirements are matched // check if all requirements are matched
var filteredTermCount = // as search terms with length < 3 are discarded: ignore
searchterms.filter(function(term){return term.length > 2}).length // as search terms with length < 3 are discarded
const filteredTermCount = [...searchTerms].filter(
(term) => term.length > 2
).length;
if ( if (
fileMap[file].length != searchterms.length && wordList.length !== searchTerms.size &&
fileMap[file].length != filteredTermCount wordList.length !== filteredTermCount
) continue; )
continue;
// ensure that none of the excluded terms is in the search result // ensure that none of the excluded terms is in the search result
for (i = 0; i < excluded.length; i++) { if (
if (terms[excluded[i]] == file || [...excludedTerms].some(
titleterms[excluded[i]] == file || (term) =>
$u.contains(terms[excluded[i]] || [], file) || terms[term] === file ||
$u.contains(titleterms[excluded[i]] || [], file)) { titleTerms[term] === file ||
valid = false; (terms[term] || []).includes(file) ||
break; (titleTerms[term] || []).includes(file)
} )
} )
break;
// if we have still a valid result we can add it to the result list // select one (max) score for the file.
if (valid) { const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w]));
// select one (max) score for the file. // add result to the result list
// for better ranking, we should calculate ranking by using words statistics like basic tf-idf... results.push([
var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]})); docNames[file],
results.push([docnames[file], titles[file], '', null, score, filenames[file]]); titles[file],
} "",
null,
score,
filenames[file],
]);
} }
return results; return results;
}, },
@ -496,34 +499,33 @@ var Search = {
/** /**
* helper function to return a node containing the * helper function to return a node containing the
* search summary for a given text. keywords is a list * search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed * of stemmed words, highlightWords is the list of normal, unstemmed
* words. the first one is used to find the occurrence, the * words. the first one is used to find the occurrence, the
* latter for highlighting it. * latter for highlighting it.
*/ */
makeSearchSummary : function(htmlText, keywords, hlwords) { makeSearchSummary: (htmlText, keywords, highlightWords) => {
var text = Search.htmlToText(htmlText); const text = Search.htmlToText(htmlText).toLowerCase();
if (text == "") { if (text === "") return null;
return null;
} const actualStartPosition = [...keywords]
var textLower = text.toLowerCase(); .map((k) => text.indexOf(k.toLowerCase()))
var start = 0; .filter((i) => i > -1)
$.each(keywords, function() { .slice(-1)[0];
var i = textLower.indexOf(this.toLowerCase()); const startWithContext = Math.max(actualStartPosition - 120, 0);
if (i > -1)
start = i; const top = startWithContext === 0 ? "" : "...";
}); const tail = startWithContext + 240 < text.length ? "..." : "";
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') + let summary = document.createElement("div");
$.trim(text.substr(start, 240)) + summary.classList.add("context");
((start + 240 - text.length) ? '...' : ''); summary.innerText = top + text.substr(startWithContext, 240).trim() + tail;
var rv = $('<p class="context"></p>').text(excerpt);
$.each(hlwords, function() { highlightWords.forEach((highlightWord) =>
rv = rv.highlightText(this, 'highlighted'); _highlightText(summary, highlightWord, "highlighted")
}); );
return rv;
} return summary;
},
}; };
$(document).ready(function() { _ready(Search.init);
Search.init();
});

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Authentication &#8212; FitTrackee 0.5.7 <title>Authentication &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,11 +128,13 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="authentication"> <section id="authentication">
<h1>Authentication<a class="headerlink" href="#authentication" title="Permalink to this headline"></a></h1> <h1>Authentication<a class="headerlink" href="#authentication" title="Permalink to this heading"></a></h1>
<dl class="http post"> <dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-register"> <dt class="sig sig-object http" id="post--api-auth-register">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/register</span></span><a class="headerlink" href="#post--api-auth-register" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/register</span></span><a class="headerlink" href="#post--api-auth-register" title="Permalink to this definition"></a></dt>
<dd><p>register a user</p> <dd><p>register a user and send confirmation email.</p>
<p>The newly created account is inactive. The user must confirm his email
to activate it.</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/register</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/register</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -138,14 +142,12 @@
</div> </div>
<p><strong>Example responses</strong>:</p> <p><strong>Example responses</strong>:</p>
<ul class="simple"> <ul class="simple">
<li><p>successful registration</p></li> <li><p>success</p></li>
</ul> </ul>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">201</span> <span class="ne">CREATED</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">SUCCESS</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;auth_token&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;JSON Web Token&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;successfully registered&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span>
</pre></div> </pre></div>
@ -163,25 +165,28 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>username</strong> (<em>string</em>) user name (3 to 12 characters required)</p></li> <li><p><strong>username</strong> (<em>string</em>) username (3 to 30 characters required)</p></li>
<li><p><strong>email</strong> (<em>string</em>) user email</p></li> <li><p><strong>email</strong> (<em>string</em>) user email</p></li>
<li><p><strong>password</strong> (<em>string</em>) password (8 characters required)</p></li> <li><p><strong>password</strong> (<em>string</em>) password (8 characters required)</p></li>
<li><p><strong>password_conf</strong> (<em>string</em>) password confirmation</p></li> <li><p><strong>lang</strong> (<em>string</em>) user language preferences (if not provided or invalid,
fallback to en (english))</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> successfully registered</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
<li><p>invalid payload</p></li> <li><p>invalid payload</p></li>
<li><p>sorry, that user already exists</p></li> <li><p>sorry, that username is already taken</p></li>
<li><dl class="simple"> <li><dl class="simple">
<dt>Errors:</dt><dd><ul> <dt>Errors:</dt><dd><ul>
<li><p>username: 3 to 12 characters required</p></li> <li><p>username: 3 to 30 characters required</p></li>
<li><p>username:
only alphanumeric characters and the underscore
character “_” allowed</p></li>
<li><p>email: valid email must be provided</p></li> <li><p>email: valid email must be provided</p></li>
<li><p>password: password and password confirmation dont match</p></li>
<li><p>password: 8 characters required</p></li> <li><p>password: 8 characters required</p></li>
</ul> </ul>
</dd> </dd>
@ -196,10 +201,84 @@
</dl> </dl>
</dd></dl> </dd></dl>
<dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-account-confirm">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/account/confirm</span></span><a class="headerlink" href="#post--api-auth-account-confirm" title="Permalink to this definition"></a></dt>
<dd><p>activate user account after registration</p>
<p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/account/confirm</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<p><strong>Example response</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;auth_token&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;JSON Web Token&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;account confirmation successful&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>token</strong> (<em>string</em>) confirmation token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> account confirmation successful</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error, please try again or contact the administrator</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-account-resend-confirmation">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/account/resend-confirmation</span></span><a class="headerlink" href="#post--api-auth-account-resend-confirmation" title="Permalink to this definition"></a></dt>
<dd><p>resend email with instructions to confirm account</p>
<p>If email sending is disabled, this endpoint is not available</p>
<p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/account/resend-confirmation</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<p><strong>Example response</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;confirmation email resent&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>email</strong> (<em>string</em>) user email</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> confirmation email resent</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">404 Not Found</a></span> the requested URL was not found on the server</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error, please try again or contact the administrator</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="http post"> <dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-login"> <dt class="sig sig-object http" id="post--api-auth-login">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/login</span></span><a class="headerlink" href="#post--api-auth-login" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/login</span></span><a class="headerlink" href="#post--api-auth-login" title="Permalink to this definition"></a></dt>
<dd><p>user login</p> <dd><p>user login</p>
<p>Only user with an active account can log in.</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/login</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/login</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -222,7 +301,7 @@
<ul class="simple"> <ul class="simple">
<li><p>error on login</p></li> <li><p>error on login</p></li>
</ul> </ul>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">404</span> <span class="ne">NOT FOUND</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">401</span> <span class="ne">UNAUTHORIZED</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span> <span class="p">{</span><span class="w"></span>
@ -232,13 +311,13 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>email</strong> (<em>string</em>) user email</p></li> <li><p><strong>email</strong> (<em>string</em>) user email</p></li>
<li><p><strong>password_conf</strong> (<em>string</em>) password confirmation</p></li> <li><p><strong>password</strong> (<em>string</em>) password</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> successfully logged in</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> successfully logged in</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
@ -249,59 +328,10 @@
</dl> </dl>
</dd></dl> </dd></dl>
<dl class="http get">
<dt class="sig sig-object http" id="get--api-auth-logout">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/auth/logout</span></span><a class="headerlink" href="#get--api-auth-logout" title="Permalink to this definition"></a></dt>
<dd><p>user logout</p>
<p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/auth/logout</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<p><strong>Example responses</strong>:</p>
<ul class="simple">
<li><p>successful logout</p></li>
</ul>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;successfully logged out&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p>error on login</p></li>
</ul>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">401</span> <span class="ne">UNAUTHORIZED</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;provide a valid auth token&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;error&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> successfully logged out</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> provide a valid auth token</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-auth-profile"> <dt class="sig sig-object http" id="get--api-auth-profile">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/auth/profile</span></span><a class="headerlink" href="#get--api-auth-profile" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/auth/profile</span></span><a class="headerlink" href="#get--api-auth-profile" title="Permalink to this definition"></a></dt>
<dd><p>get authenticated user info</p> <dd><p>get authenticated user info (profile, account, preferences)</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/auth/profile</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/auth/profile</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -320,6 +350,7 @@
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_active&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -380,12 +411,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success.</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success.</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -402,7 +433,7 @@
<dl class="http post"> <dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-profile-edit"> <dt class="sig sig-object http" id="post--api-auth-profile-edit">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/profile/edit</span></span><a class="headerlink" href="#post--api-auth-profile-edit" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/profile/edit</span></span><a class="headerlink" href="#post--api-auth-profile-edit" title="Permalink to this definition"></a></dt>
<dd><p>edit authenticated user</p> <dd><p>edit authenticated user profile</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/profile/edit</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/profile/edit</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -421,6 +452,7 @@
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_active&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -482,28 +514,25 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>first_name</strong> (<em>string</em>) user first name</p></li> <li><p><strong>first_name</strong> (<em>string</em>) user first name</p></li>
<li><p><strong>last_name</strong> (<em>string</em>) user last name</p></li> <li><p><strong>last_name</strong> (<em>string</em>) user last name</p></li>
<li><p><strong>location</strong> (<em>string</em>) user location</p></li> <li><p><strong>location</strong> (<em>string</em>) user location</p></li>
<li><p><strong>bio</strong> (<em>string</em>) user biography</p></li> <li><p><strong>bio</strong> (<em>string</em>) user biography</p></li>
<li><p><strong>birth_date</strong> (<em>string</em>) user birth date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span></code>)</p></li> <li><p><strong>birth_date</strong> (<em>string</em>) user birth date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span></code>)</p></li>
<li><p><strong>password</strong> (<em>string</em>) user password</p></li>
<li><p><strong>password_conf</strong> (<em>string</em>) user password confirmation</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user profile updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user profile updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
<li><p>invalid payload</p></li> <li><p>invalid payload</p></li>
<li><p>password: password and password confirmation dont match</p></li>
</ul> </ul>
</p></li> </p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -540,6 +569,7 @@
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_active&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -601,19 +631,20 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>timezone</strong> (<em>string</em>) user time zone</p></li> <li><p><strong>timezone</strong> (<em>string</em>) user time zone</p></li>
<li><p><strong>weekm</strong> (<em>string</em>) does week start on Monday?</p></li> <li><p><strong>weekm</strong> (<em>boolean</em>) does week start on Monday?</p></li>
<li><p><strong>language</strong> (<em>string</em>) language preferences</p></li> <li><p><strong>language</strong> (<em>string</em>) language preferences</p></li>
<li><p><strong>imperial_units</strong> (<em>boolean</em>) display distance in imperial units</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user preferences updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user preferences updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
@ -660,19 +691,19 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>color</strong> (<em>string</em>) valid hexadecimal color</p></li> <li><p><strong>color</strong> (<em>string</em>) valid hexadecimal color</p></li>
<li><p><strong>is_active</strong> (<em>boolean</em>) is sport available when adding a workout</p></li> <li><p><strong>is_active</strong> (<em>boolean</em>) is sport available when adding a workout</p></li>
<li><p><strong>stopped_speed_threshold</strong> (<em>float</em>) stopped speed threshold used by gpxpy</p></li> <li><p><strong>stopped_speed_threshold</strong> (<em>float</em>) stopped speed threshold used by gpxpy</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user preferences updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user preferences updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
@ -711,17 +742,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>sport_id</strong> (<em>string</em>) sport id</p></li> <li><p><strong>sport_id</strong> (<em>string</em>) sport id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> user preferences deleted</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> user preferences deleted</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -760,17 +791,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Form Parameters</dt> <dt class="field-odd">Form Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>file</strong> image file (allowed extensions: .jpg, .png, .gif)</p></li> <li><p><strong>file</strong> image file (allowed extensions: .jpg, .png, .gif)</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user picture updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user picture updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
@ -808,12 +839,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> picture deleted</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> picture deleted</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -832,6 +863,7 @@
<dt class="sig sig-object http" id="post--api-auth-password-reset-request"> <dt class="sig sig-object http" id="post--api-auth-password-reset-request">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/password/reset-request</span></span><a class="headerlink" href="#post--api-auth-password-reset-request" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/password/reset-request</span></span><a class="headerlink" href="#post--api-auth-password-reset-request" title="Permalink to this definition"></a></dt>
<dd><p>handle password reset request</p> <dd><p>handle password reset request</p>
<p>If email sending is disabled, this endpoint is not available</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/password/reset-request</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/password/reset-request</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -848,15 +880,146 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>email</strong> (<em>string</em>) user email</p></li> <li><p><strong>email</strong> (<em>string</em>) user email</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> password reset request processed</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> password reset request processed</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">404 Not Found</a></span> the requested URL was not found on the server</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="http patch">
<dt class="sig sig-object http" id="patch--api-auth-profile-edit-account">
<span class="sig-name descname"><span class="pre">PATCH</span> </span><span class="sig-name descname"><span class="pre">/api/auth/profile/edit/account</span></span><a class="headerlink" href="#patch--api-auth-profile-edit-account" title="Permalink to this definition"></a></dt>
<dd><p>update authenticated user email and password</p>
<p>It sends emails if sending is enabled:</p>
<ul class="simple">
<li><p>Password change</p></li>
<li><p>Email change:</p>
<ul>
<li><p>one to the current address to inform user</p></li>
<li><p>another one to the new address to confirm it.</p></li>
</ul>
</li>
</ul>
<p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">PATCH</span> <span class="nn">/api/auth/profile/edit/account</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<p><strong>Example response</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;admin&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;bio&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;birth_date&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;created_at&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 14 Jul 2019 14:09:58 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_active&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;nb_sports&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">6</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;picture&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;records&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">9</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;record_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;AS&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;sport_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;user&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;value&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">18</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_date&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 07 Jul 2019 08:00:00 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;hvYBqYBRa7wwXpaStWR4V2&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;record_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;FD&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;sport_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;user&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;value&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">18</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_date&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 07 Jul 2019 08:00:00 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;hvYBqYBRa7wwXpaStWR4V2&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;record_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;LD&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;sport_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;user&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;value&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;1:01:00&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_date&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 07 Jul 2019 08:00:00 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;hvYBqYBRa7wwXpaStWR4V2&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;record_type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;MS&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;sport_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;user&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;value&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">18</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_date&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 07 Jul 2019 08:00:00 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;workout_id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;hvYBqYBRa7wwXpaStWR4V2&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;sports_list&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="mi">6</span><span class="w"></span>
<span class="w"> </span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;timezone&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Europe/Paris&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;total_distance&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">67.895</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;total_duration&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;6:50:27&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;username&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;sam&quot;</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;weekm&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;user account updated&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>email</strong> (<em>string</em>) user email</p></li>
<li><p><strong>password</strong> (<em>string</em>) user current password</p></li>
<li><p><strong>new_password</strong> (<em>string</em>) user new password</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> user account updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
<li><p>invalid payload</p></li>
<li><p>email is missing</p></li>
<li><p>current password is missing</p></li>
<li><p>email: valid email must be provided</p></li>
<li><p>password: 8 characters required</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
<li><p>signature expired, please log in again</p></li>
<li><p>invalid token, please log in again</p></li>
<li><p>invalid credentials</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error, please try again or contact the administrator</p></li>
</ul> </ul>
</dd> </dd>
</dl> </dl>
@ -865,7 +1028,8 @@
<dl class="http post"> <dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-password-update"> <dt class="sig sig-object http" id="post--api-auth-password-update">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/password/update</span></span><a class="headerlink" href="#post--api-auth-password-update" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/password/update</span></span><a class="headerlink" href="#post--api-auth-password-update" title="Permalink to this definition"></a></dt>
<dd><p>update user password</p> <dd><p>update user password after password reset request</p>
<p>It sends emails if sending is enabled</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/password/update</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/password/update</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -882,14 +1046,13 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>password</strong> (<em>string</em>) password (8 characters required)</p></li> <li><p><strong>password</strong> (<em>string</em>) password (8 characters required)</p></li>
<li><p><strong>password_conf</strong> (<em>string</em>) password confirmation</p></li>
<li><p><strong>token</strong> (<em>string</em>) password reset token</p></li> <li><p><strong>token</strong> (<em>string</em>) password reset token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> password updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> password updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
@ -900,6 +1063,41 @@
</dl> </dl>
</dd></dl> </dd></dl>
<dl class="http post">
<dt class="sig sig-object http" id="post--api-auth-email-update">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/auth/email/update</span></span><a class="headerlink" href="#post--api-auth-email-update" title="Permalink to this definition"></a></dt>
<dd><p>update user email after confirmation</p>
<p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/auth/email/update</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<p><strong>Example response</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;email updated&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>token</strong> (<em>string</em>) password reset token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> email updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error, please try again or contact the administrator</p></li>
</ul>
</dd>
</dl>
</dd></dl>
</section> </section>
@ -915,7 +1113,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Configuration &#8212; FitTrackee 0.5.7 <title>Configuration &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="configuration"> <section id="configuration">
<h1>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline"></a></h1> <h1>Configuration<a class="headerlink" href="#configuration" title="Permalink to this heading"></a></h1>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-config"> <dt class="sig sig-object http" id="get--api-config">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/config</span></span><a class="headerlink" href="#get--api-config" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/config</span></span><a class="headerlink" href="#get--api-config" title="Permalink to this definition"></a></dt>
@ -142,20 +144,22 @@
<span class="p">{</span><span class="w"></span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;admin_contact&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_email_sending_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;version&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;0.5.7&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;version&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;0.6.10&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span> <span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span>
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error on getting configuration</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error on getting configuration</p></li>
@ -180,32 +184,37 @@
<span class="p">{</span><span class="w"></span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;admin_contact&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;is_email_sending_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;version&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;0.6.10&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span> <span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span>
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>admin_contact</strong> (<em>string</em>) email to contact the administrator</p></li>
<li><p><strong>gpx_limit_import</strong> (<em>integer</em>) max number of files in zip archive</p></li> <li><p><strong>gpx_limit_import</strong> (<em>integer</em>) max number of files in zip archive</p></li>
<li><p><strong>is_registration_enabled</strong> (<em>boolean</em>) is registration enabled ?</p></li> <li><p><strong>is_registration_enabled</strong> (<em>boolean</em>) is registration enabled ?</p></li>
<li><p><strong>max_single_file_size</strong> (<em>integer</em>) max size of a single file</p></li> <li><p><strong>max_single_file_size</strong> (<em>integer</em>) max size of a single file</p></li>
<li><p><strong>max_zip_file_size</strong> (<em>integer</em>) max size of a zip archive</p></li>
<li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li> <li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li>
<li><p><strong>max_zip_file_size</strong> (<em>integer</em>) max size of a zip archive</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
@ -213,6 +222,7 @@
<li><p>provide a valid auth token</p></li> <li><p>provide a valid auth token</p></li>
<li><p>signature expired, please log in again</p></li> <li><p>signature expired, please log in again</p></li>
<li><p>invalid token, please log in again</p></li> <li><p>invalid token, please log in again</p></li>
<li><p>valid email must be provided for admin contact</p></li>
</ul> </ul>
</p></li> </p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4">403 Forbidden</a></span> you do not have permissions</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4">403 Forbidden</a></span> you do not have permissions</p></li>
@ -242,7 +252,7 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
</ul> </ul>
@ -265,7 +275,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>API documentation &#8212; FitTrackee 0.5.7 <title>API documentation &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,11 +13,12 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Authentication" href="auth.html" /> <link rel="next" title="Authentication" href="auth.html" />
<link rel="prev" title="Installation" href="../installation.html" /> <link rel="prev" title="Command line interface" href="../cli.html" />
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'> <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">API documentation</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -87,7 +89,7 @@
<li> <li>
<a href="../installation.html" title="Previous Chapter: Installation"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Installation</span> <a href="../cli.html" title="Previous Chapter: Command line interface"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Command line ...</span>
</a> </a>
</li> </li>
<li> <li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="api-documentation"> <section id="api-documentation">
<h1>API documentation<a class="headerlink" href="#api-documentation" title="Permalink to this headline"></a></h1> <h1>API documentation<a class="headerlink" href="#api-documentation" title="Permalink to this heading"></a></h1>
<div class="toctree-wrapper compound"> <div class="toctree-wrapper compound">
<p class="caption" role="heading"><span class="caption-text">Endpoints:</span></p> <p class="caption" role="heading"><span class="caption-text">Endpoints:</span></p>
<ul> <ul>
@ -154,7 +156,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Records &#8212; FitTrackee 0.5.7 <title>Records &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="records"> <section id="records">
<h1>Records<a class="headerlink" href="#records" title="Permalink to this headline"></a></h1> <h1>Records<a class="headerlink" href="#records" title="Permalink to this heading"></a></h1>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-records"> <dt class="sig sig-object http" id="get--api-records">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/records</span></span><a class="headerlink" href="#get--api-records" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/records</span></span><a class="headerlink" href="#get--api-records" title="Permalink to this definition"></a></dt>
@ -212,12 +214,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -246,7 +248,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Sports &#8212; FitTrackee 0.5.7 <title>Sports &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="sports"> <section id="sports">
<h1>Sports<a class="headerlink" href="#sports" title="Permalink to this headline"></a></h1> <h1>Sports<a class="headerlink" href="#sports" title="Permalink to this heading"></a></h1>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-sports"> <dt class="sig sig-object http" id="get--api-sports">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/sports</span></span><a class="headerlink" href="#get--api-sports" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/sports</span></span><a class="headerlink" href="#get--api-sports" title="Permalink to this definition"></a></dt>
@ -270,12 +272,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -361,17 +363,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li> <li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -436,22 +438,22 @@ Authenticated user must be an admin</p>
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li> <li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request JSON Object</dt> <dt class="field-even">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><strong>is_active</strong> (<em>string</em>) sport active status</p></li> <li><p><strong>is_active</strong> (<em>string</em>) sport active status</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> sport updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> sport updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
@ -484,7 +486,7 @@ Authenticated user must be an admin</p>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Statistics &#8212; FitTrackee 0.5.7 <title>Statistics &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="statistics"> <section id="statistics">
<h1>Statistics<a class="headerlink" href="#statistics" title="Permalink to this headline"></a></h1> <h1>Statistics<a class="headerlink" href="#statistics" title="Permalink to this heading"></a></h1>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-stats-(user_name)-by_time"> <dt class="sig sig-object http" id="get--api-stats-(user_name)-by_time">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/stats/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/by_time</span></span><a class="headerlink" href="#get--api-stats-(user_name)-by_time" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/stats/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/by_time</span></span><a class="headerlink" href="#get--api-stats-(user_name)-by_time" title="Permalink to this definition"></a></dt>
@ -204,12 +206,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li> <li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Query Parameters</dt> <dt class="field-even">Query Parameters<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><strong>from</strong> (<em>string</em>) start date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span></code>)</p></li> <li><p><strong>from</strong> (<em>string</em>) start date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span></code>)</p></li>
<li><p><strong>to</strong> (<em>string</em>) end date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span></code>)</p></li> <li><p><strong>to</strong> (<em>string</em>) end date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span></code>)</p></li>
@ -223,12 +225,12 @@
</p></li> </p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -318,22 +320,22 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li> <li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Query Parameters</dt> <dt class="field-even">Query Parameters<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li> <li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -376,12 +378,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -411,7 +413,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Users &#8212; FitTrackee 0.5.7 <title>Users &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,11 +128,13 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="users"> <section id="users">
<h1>Users<a class="headerlink" href="#users" title="Permalink to this headline"></a></h1> <h1>Users<a class="headerlink" href="#users" title="Permalink to this heading"></a></h1>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-users"> <dt class="sig sig-object http" id="get--api-users">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/users</span></span><a class="headerlink" href="#get--api-users" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/users</span></span><a class="headerlink" href="#get--api-users" title="Permalink to this definition"></a></dt>
<dd><p>Get all users</p> <dd><p>Get all users (regardless their account status), if authenticated user
has admin rights</p>
<p>It returns user preferences only for authenticated user.</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<ul class="simple"> <ul class="simple">
<li><p>without parameters</p></li> <li><p>without parameters</p></li>
@ -160,6 +164,7 @@
<span class="w"> </span><span class="nt">&quot;created_at&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 14 Jul 2019 14:09:58 GMT&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;created_at&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sun, 14 Jul 2019 14:09:58 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_admin&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -213,7 +218,8 @@
<span class="w"> </span><span class="nt">&quot;timezone&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Europe/Paris&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;timezone&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Europe/Paris&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;total_distance&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">67.895</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;total_distance&quot;</span><span class="p">:</span><span class="w"> </span><span class="mf">67.895</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;total_duration&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;6:50:27&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;total_duration&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;6:50:27&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;username&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;username&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;weekm&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span> <span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;admin&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;admin&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
@ -222,6 +228,7 @@
<span class="w"> </span><span class="nt">&quot;created_at&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sat, 20 Jul 2019 11:27:03 GMT&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;created_at&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Sat, 20 Jul 2019 11:27:03 GMT&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;sam@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_admin&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;fr&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;fr&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -242,22 +249,22 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Query Parameters</dt> <dt class="field-odd">Query Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li> <li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li>
<li><p><strong>per_page</strong> (<em>integer</em>) number of users per page (default: 10, max: 50)</p></li> <li><p><strong>per_page</strong> (<em>integer</em>) number of users per page (default: 10, max: 50)</p></li>
<li><p><strong>q</strong> (<em>string</em>) query on user name</p></li> <li><p><strong>q</strong> (<em>string</em>) query on user name</p></li>
<li><p><strong>order_by</strong> (<em>string</em>) sorting criteria (<code class="docutils literal notranslate"><span class="pre">username</span></code>, <code class="docutils literal notranslate"><span class="pre">created_at</span></code>, <li><p><strong>order_by</strong> (<em>string</em>) sorting criteria (<code class="docutils literal notranslate"><span class="pre">username</span></code>, <code class="docutils literal notranslate"><span class="pre">created_at</span></code>,
<code class="docutils literal notranslate"><span class="pre">workouts_count</span></code>, <code class="docutils literal notranslate"><span class="pre">admin</span></code>)</p></li> <code class="docutils literal notranslate"><span class="pre">workouts_count</span></code>, <code class="docutils literal notranslate"><span class="pre">admin</span></code>, <code class="docutils literal notranslate"><span class="pre">is_active</span></code>)</p></li>
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">asc</span></code>)</p></li> <li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">asc</span></code>)</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -274,7 +281,9 @@
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-users-(user_name)"> <dt class="sig sig-object http" id="get--api-users-(user_name)">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/users/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-users-(user_name)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/users/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-users-(user_name)" title="Permalink to this definition"></a></dt>
<dd><p>Get single user details</p> <dd><p>Get single user details. Only user with admin rights can get other users
details.</p>
<p>It returns user preferences only for authenticated user.</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/users/admin</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/users/admin</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -294,6 +303,7 @@
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_admin&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -354,17 +364,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li> <li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -397,12 +407,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li> <li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">404 Not Found</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">404 Not Found</a></span> <ul>
@ -418,10 +428,17 @@
<dl class="http patch"> <dl class="http patch">
<dt class="sig sig-object http" id="patch--api-users-(user_name)"> <dt class="sig sig-object http" id="patch--api-users-(user_name)">
<span class="sig-name descname"><span class="pre">PATCH</span> </span><span class="sig-name descname"><span class="pre">/api/users/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><a class="headerlink" href="#patch--api-users-(user_name)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">PATCH</span> </span><span class="sig-name descname"><span class="pre">/api/users/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><a class="headerlink" href="#patch--api-users-(user_name)" title="Permalink to this definition"></a></dt>
<dd><p>Update user to add admin rights</p> <dd><p>Update user account</p>
<ul class="simple">
<li><p>add/remove admin rights (regardless user account status)</p></li>
<li><p>reset password (and send email to update user password,
if sending enabled)</p></li>
<li><p>update user email (and send email to new user email, if sending enabled)</p></li>
<li><p>activate account for an inactive user</p></li>
</ul>
<p>Only user with admin rights can modify another user</p> <p>Only user with admin rights can modify another user</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">PATCH</span> <span class="nn">api/users/&lt;user_name&gt;</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">PATCH</span> <span class="nn">/api/users/&lt;user_name&gt;</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div> </pre></div>
</div> </div>
@ -439,6 +456,7 @@
<span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;email&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;first_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;imperial_units&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_active&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;language&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;en&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;last_name&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;location&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
@ -499,24 +517,33 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>user_name</strong> (<em>string</em>) user name</p></li> <li><p><strong>user_name</strong> (<em>string</em>) user name</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request JSON Object</dt> <dt class="field-even">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><strong>activate</strong> (<em>boolean</em>) activate user account</p></li>
<li><p><strong>admin</strong> (<em>boolean</em>) does the user have administrator rights</p></li> <li><p><strong>admin</strong> (<em>boolean</em>) does the user have administrator rights</p></li>
<li><p><strong>new_email</strong> (<em>boolean</em>) new user email</p></li>
<li><p><strong>reset_password</strong> (<em>boolean</em>) reset user password</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
<li><p>invalid payload</p></li>
<li><p>valid email must be provided</p></li>
<li><p>new email must be different than curent email</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li> <li><p>provide a valid auth token</p></li>
<li><p>signature expired, please log in again</p></li> <li><p>signature expired, please log in again</p></li>
@ -552,17 +579,17 @@ one admin</p>
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>user_name</strong> (<em>string</em>) user name</p></li> <li><p><strong>user_name</strong> (<em>string</em>) user name</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> user account deleted</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> user account deleted</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -601,7 +628,7 @@ one admin</p>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Workouts &#8212; FitTrackee 0.5.7 <title>Workouts &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="../troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="workouts"> <section id="workouts">
<h1>Workouts<a class="headerlink" href="#workouts" title="Permalink to this headline"></a></h1> <h1>Workouts<a class="headerlink" href="#workouts" title="Permalink to this heading"></a></h1>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-workouts"> <dt class="sig sig-object http" id="get--api-workouts">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts</span></span><a class="headerlink" href="#get--api-workouts" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts</span></span><a class="headerlink" href="#get--api-workouts" title="Permalink to this definition"></a></dt>
@ -241,7 +243,7 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Query Parameters</dt> <dt class="field-odd">Query Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li> <li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li>
<li><p><strong>per_page</strong> (<em>integer</em>) number of workouts per page <li><p><strong>per_page</strong> (<em>integer</em>) number of workouts per page
@ -260,12 +262,12 @@
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">desc</span></code>)</p></li> <li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">desc</span></code>)</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -283,7 +285,7 @@
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)"> <dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)" title="Permalink to this definition"></a></dt>
<dd><p>Get an workout</p> <dd><p>Get a workout</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
</pre></div> </pre></div>
@ -348,17 +350,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -377,7 +379,7 @@
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-gpx"> <dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-gpx">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/gpx</span></span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-gpx" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/gpx</span></span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-gpx" title="Permalink to this definition"></a></dt>
<dd><p>Get gpx file for an workout displayed on map with Leaflet</p> <dd><p>Get gpx file for a workout displayed on map with Leaflet</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/gpx</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/gpx</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -397,17 +399,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -430,7 +432,7 @@
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-chart_data"> <dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-chart_data">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/chart_data</span></span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-chart_data" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/chart_data</span></span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-chart_data" title="Permalink to this definition"></a></dt>
<dd><p>Get chart data from an workout gpx file, to display it with Recharts</p> <dd><p>Get chart data from a workout gpx file, to display it with Recharts</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/chart</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/chart</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -469,17 +471,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -502,7 +504,7 @@
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-chart_data-segment-(int-segment_id)"> <dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-chart_data-segment-(int-segment_id)">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/chart_data/segment/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">int:</span> </em><em class="sig-param"><span class="pre">segment_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-chart_data-segment-(int-segment_id)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/chart_data/segment/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">int:</span> </em><em class="sig-param"><span class="pre">segment_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-chart_data-segment-(int-segment_id)" title="Permalink to this definition"></a></dt>
<dd><p>Get chart data from an workout gpx file, to display it with Recharts</p> <dd><p>Get chart data from a workout gpx file, to display it with Recharts</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/chart/segment/0</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/chart/segment/0</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -541,18 +543,18 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
<li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li> <li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> no gpx file for this workout</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> no gpx file for this workout</p></li>
@ -572,7 +574,7 @@
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-gpx-segment-(int-segment_id)"> <dt class="sig sig-object http" id="get--api-workouts-(string-workout_short_id)-gpx-segment-(int-segment_id)">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/gpx/segment/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">int:</span> </em><em class="sig-param"><span class="pre">segment_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-gpx-segment-(int-segment_id)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><span class="sig-name descname"><span class="pre">/gpx/segment/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">int:</span> </em><em class="sig-param"><span class="pre">segment_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-workouts-(string-workout_short_id)-gpx-segment-(int-segment_id)" title="Permalink to this definition"></a></dt>
<dd><p>Get gpx file for an workout segment displayed on map with Leaflet</p> <dd><p>Get gpx file for a workout segment displayed on map with Leaflet</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/gpx/segment/0</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF/gpx/segment/0</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -592,18 +594,18 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
<li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li> <li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> no gpx file for this workout</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> no gpx file for this workout</p></li>
@ -635,12 +637,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>map_id</strong> (<em>string</em>) workout map id</p></li> <li><p><strong>map_id</strong> (<em>string</em>) workout map id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -670,7 +672,7 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>s</strong> (<em>string</em>) subdomain</p></li> <li><p><strong>s</strong> (<em>string</em>) subdomain</p></li>
<li><p><strong>z</strong> (<em>string</em>) zoom</p></li> <li><p><strong>z</strong> (<em>string</em>) zoom</p></li>
@ -696,12 +698,12 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -723,7 +725,7 @@
<dl class="http post"> <dl class="http post">
<dt class="sig sig-object http" id="post--api-workouts"> <dt class="sig sig-object http" id="post--api-workouts">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/workouts</span></span><a class="headerlink" href="#post--api-workouts" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/workouts</span></span><a class="headerlink" href="#post--api-workouts" title="Permalink to this definition"></a></dt>
<dd><p>Post an workout with a gpx file</p> <dd><p>Post a workout with a gpx file</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/workouts/</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/workouts/</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">multipart/form-data</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">multipart/form-data</span>
@ -809,18 +811,18 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Form Parameters</dt> <dt class="field-odd">Form Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>file</strong> gpx file (allowed extensions: .gpx, .zip)</p></li> <li><p><strong>file</strong> gpx file (allowed extensions: .gpx, .zip)</p></li>
<li><p><strong>data</strong> sport id and notes (example: <code class="docutils literal notranslate"><span class="pre">{&quot;sport_id&quot;:</span> <span class="pre">1,</span> <span class="pre">&quot;notes&quot;:</span> <span class="pre">&quot;&quot;}</span></code>)</p></li> <li><p><strong>data</strong> sport id and notes (example: <code class="docutils literal notranslate"><span class="pre">{&quot;sport_id&quot;:</span> <span class="pre">1,</span> <span class="pre">&quot;notes&quot;:</span> <span class="pre">&quot;&quot;}</span></code>)</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
@ -846,7 +848,7 @@
<dl class="http post"> <dl class="http post">
<dt class="sig sig-object http" id="post--api-workouts-no_gpx"> <dt class="sig sig-object http" id="post--api-workouts-no_gpx">
<span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/no_gpx</span></span><a class="headerlink" href="#post--api-workouts-no_gpx" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">POST</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/no_gpx</span></span><a class="headerlink" href="#post--api-workouts-no_gpx" title="Permalink to this definition"></a></dt>
<dd><p>Post an workout without gpx file</p> <dd><p>Post a workout without gpx file</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/workouts/no_gpx</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/api/workouts/no_gpx</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -932,9 +934,10 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_date</strong> (<em>string</em>) workout date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span> <span class="pre">%H:%M</span></code>)</p></li> <li><p><strong>workout_date</strong> (<em>string</em>) workout date, in user timezone
(format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span> <span class="pre">%H:%M</span></code>)</p></li>
<li><p><strong>distance</strong> (<em>float</em>) workout distance in km</p></li> <li><p><strong>distance</strong> (<em>float</em>) workout distance in km</p></li>
<li><p><strong>duration</strong> (<em>integer</em>) workout duration in seconds</p></li> <li><p><strong>duration</strong> (<em>integer</em>) workout duration in seconds</p></li>
<li><p><strong>notes</strong> (<em>string</em>) notes (not mandatory)</p></li> <li><p><strong>notes</strong> (<em>string</em>) notes (not mandatory)</p></li>
@ -942,12 +945,12 @@
<li><p><strong>title</strong> (<em>string</em>) workout title</p></li> <li><p><strong>title</strong> (<em>string</em>) workout title</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
@ -966,7 +969,7 @@
<dl class="http patch"> <dl class="http patch">
<dt class="sig sig-object http" id="patch--api-workouts-(string-workout_short_id)"> <dt class="sig sig-object http" id="patch--api-workouts-(string-workout_short_id)">
<span class="sig-name descname"><span class="pre">PATCH</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#patch--api-workouts-(string-workout_short_id)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">PATCH</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#patch--api-workouts-(string-workout_short_id)" title="Permalink to this definition"></a></dt>
<dd><p>Update an workout</p> <dd><p>Update a workout</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">PATCH</span> <span class="nn">/api/workouts/1</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">PATCH</span> <span class="nn">/api/workouts/1</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -1052,14 +1055,15 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request JSON Object</dt> <dt class="field-even">Request JSON Object<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><strong>workout_date</strong> (<em>string</em>) workout date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span> <span class="pre">%H:%M</span></code>) <li><p><strong>workout_date</strong> (<em>string</em>) workout date in user timezone
(format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span> <span class="pre">%H:%M</span></code>)
(only for workout without gpx)</p></li> (only for workout without gpx)</p></li>
<li><p><strong>distance</strong> (<em>float</em>) workout distance in km <li><p><strong>distance</strong> (<em>float</em>) workout distance in km
(only for workout without gpx)</p></li> (only for workout without gpx)</p></li>
@ -1070,12 +1074,12 @@
<li><p><strong>title</strong> (<em>string</em>) workout title</p></li> <li><p><strong>title</strong> (<em>string</em>) workout title</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Status Codes</dt> <dt class="field-even">Status Codes<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> workout updated</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> workout updated</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
@ -1095,7 +1099,7 @@
<dl class="http delete"> <dl class="http delete">
<dt class="sig sig-object http" id="delete--api-workouts-(string-workout_short_id)"> <dt class="sig sig-object http" id="delete--api-workouts-(string-workout_short_id)">
<span class="sig-name descname"><span class="pre">DELETE</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#delete--api-workouts-(string-workout_short_id)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">DELETE</span> </span><span class="sig-name descname"><span class="pre">/api/workouts/</span></span><span class="sig-paren">(</span><em class="property"><span class="pre">string:</span> </em><em class="sig-param"><span class="pre">workout_short_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#delete--api-workouts-(string-workout_short_id)" title="Permalink to this definition"></a></dt>
<dd><p>Delete an workout</p> <dd><p>Delete a workout</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">DELETE</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">DELETE</span> <span class="nn">/api/workouts/kjxavSTUrJvoAh2wvCeGEF</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span> <span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
@ -1107,17 +1111,17 @@
</pre></div> </pre></div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li> <li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>
<dd class="field-even"><ul class="simple"> <dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li> <li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Status Codes</dt> <dt class="field-odd">Status Codes<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> workout deleted</p></li> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> workout deleted</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul> <li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -1148,7 +1152,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

File diff suppressed because it is too large Load Diff

237
docs/cli.html Normal file
View File

@ -0,0 +1,237 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Command line interface &#8212; FitTrackee 0.6.10
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="API documentation" href="api/index.html" />
<link rel="prev" title="Installation" href="installation.html" />
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
<meta name="apple-mobile-web-app-capable" content="yes">
<script type="text/javascript" src="_static/js/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="_static/js/jquery-fix.js"></script>
<script type="text/javascript" src="_static/bootstrap-3.4.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
</head><body>
<div id="navbar" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span>
</div>
<div class="collapse navbar-collapse nav-collapse">
<ul class="nav navbar-nav">
<li><a href="https://github.com/SamR1/FitTrackee">GitHub</a></li>
<li class="dropdown globaltoc-container">
<a role="button"
id="dLabelGlobalToc"
data-toggle="dropdown"
data-target="#"
href="index.html">Docs <b class="caret"></b></a>
<ul class="dropdown-menu globaltoc"
role="menu"
aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
</ul>
</ul>
</li>
<li class="dropdown">
<a role="button"
id="dLabelLocalToc"
data-toggle="dropdown"
data-target="#"
href="#">Page <b class="caret"></b></a>
<ul class="dropdown-menu localtoc"
role="menu"
aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Command line interface</a><ul>
<li><a class="reference internal" href="#database">Database</a><ul>
<li><a class="reference internal" href="#ftcli-db-upgrade"><code class="docutils literal notranslate"><span class="pre">ftcli</span> <span class="pre">db</span> <span class="pre">upgrade</span></code></a></li>
<li><a class="reference internal" href="#ftcli-db-drop"><code class="docutils literal notranslate"><span class="pre">ftcli</span> <span class="pre">db</span> <span class="pre">drop</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#users">Users</a><ul>
<li><a class="reference internal" href="#ftcli-users-update"><code class="docutils literal notranslate"><span class="pre">ftcli</span> <span class="pre">users</span> <span class="pre">update</span></code></a></li>
</ul>
</li>
</ul>
</li>
</ul>
</ul>
</li>
<li>
<a href="installation.html" title="Previous Chapter: Installation"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Installation</span>
</a>
</li>
<li>
<a href="api/index.html" title="Next Chapter: API documentation"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">API documentation &raquo;</span>
</a>
</li>
<li class="hidden-sm">
<div id="sourcelink">
<a href="_sources/cli.rst.txt"
rel="nofollow">Source</a>
</div></li>
</ul>
<form class="navbar-form navbar-right" action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="body col-md-12 content" role="main">
<section id="command-line-interface">
<h1>Command line interface<a class="headerlink" href="#command-line-interface" title="Permalink to this heading"></a></h1>
<p>A command line interface (CLI) is available to manage database and users.</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ ftcli
Usage: ftcli <span class="o">[</span>OPTIONS<span class="o">]</span> COMMAND <span class="o">[</span>ARGS<span class="o">]</span>...
FitTrackee Command Line Interface
Options:
--help Show this message and exit.
Commands:
db Manage database.
users Manage users.
</pre></div>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">The following commands are now deprecated and will be removed in a next version:</div>
<div class="line">- <code class="docutils literal notranslate"><span class="pre">fittrackee_set_admin</span></code></div>
<div class="line">- <code class="docutils literal notranslate"><span class="pre">fittrackee_upgrade_db</span></code></div>
</div>
</div>
<section id="database">
<h2>Database<a class="headerlink" href="#database" title="Permalink to this heading"></a></h2>
<section id="ftcli-db-upgrade">
<h3><code class="docutils literal notranslate"><span class="pre">ftcli</span> <span class="pre">db</span> <span class="pre">upgrade</span></code><a class="headerlink" href="#ftcli-db-upgrade" title="Permalink to this heading"></a></h3>
<div class="versionadded">
<p><span class="versionmodified added">New in version 0.6.5.</span></p>
</div>
<p>Apply migrations.</p>
</section>
<section id="ftcli-db-drop">
<h3><code class="docutils literal notranslate"><span class="pre">ftcli</span> <span class="pre">db</span> <span class="pre">drop</span></code><a class="headerlink" href="#ftcli-db-drop" title="Permalink to this heading"></a></h3>
<div class="versionadded">
<p><span class="versionmodified added">New in version 0.6.5.</span></p>
</div>
<p>Empty database and delete uploaded files, only on development environments.</p>
</section>
</section>
<section id="users">
<h2>Users<a class="headerlink" href="#users" title="Permalink to this heading"></a></h2>
<section id="ftcli-users-update">
<h3><code class="docutils literal notranslate"><span class="pre">ftcli</span> <span class="pre">users</span> <span class="pre">update</span></code><a class="headerlink" href="#ftcli-users-update" title="Permalink to this heading"></a></h3>
<div class="versionadded">
<p><span class="versionmodified added">New in version 0.6.5.</span></p>
</div>
<p>Modify a user account (admin rights, active status, email and password).</p>
<table class="table-bordered docutils align-default">
<colgroup>
<col style="width: 33%" />
<col style="width: 67%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Options</p></th>
<th class="head"><p>Description</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">--set-admin</span> <span class="pre">BOOLEAN</span></code></p></td>
<td><p>Add/remove admin rights (when adding admin rights, it also activates user account if not active).</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">--activate</span></code></p></td>
<td><p>Activate user account.</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">--reset-password</span></code></p></td>
<td><p>Reset user password (a new password will be displayed).</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">--update-email</span> <span class="pre">EMAIL</span></code></p></td>
<td><p>Update user email.</p></td>
</tr>
</tbody>
</table>
</section>
</section>
</section>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<p class="pull-right">
<a href="#">Back to top</a>
</p>
<p>
&copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p>
</div>
</footer>
</body>
</html>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Features &#8212; FitTrackee 0.5.7 <title>Features &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script> <script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script> <script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script> <script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">Features</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -140,9 +142,9 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="features"> <section id="features">
<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 heading"></a></h1>
<section id="workouts"> <section id="workouts">
<h2>Workouts<a class="headerlink" href="#workouts" title="Permalink to this headline"></a></h2> <h2>Workouts<a class="headerlink" href="#workouts" title="Permalink to this heading"></a></h2>
<ul class="simple"> <ul class="simple">
<li><dl class="simple"> <li><dl class="simple">
<dt>11 sports are supported:</dt><dd><ul> <dt>11 sports are supported:</dt><dd><ul>
@ -209,13 +211,19 @@
<li><dl class="simple"> <li><dl class="simple">
<dt>User records by sports:</dt><dd><ul class="simple"> <dt>User records by sports:</dt><dd><ul class="simple">
<li><p>average speed</p></li> <li><p>average speed</p></li>
<li><p>farest distance</p></li> <li><p>farthest distance</p></li>
<li><p>longest duration</p></li> <li><p>longest duration</p></li>
<li><p>maximum speed</p></li> <li><p>maximum speed</p></li>
</ul> </ul>
</dd> </dd>
</dl> </dl>
</li> </li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Records may differ from records displayed by the application that originally generated the gpx files.</p>
</div>
<ul class="simple">
<li><p>Workouts list and filter. Only sports with workouts are displayed in sport dropdown.</p></li> <li><p>Workouts list and filter. Only sports with workouts are displayed in sport dropdown.</p></li>
</ul> </ul>
<div class="admonition note"> <div class="admonition note">
@ -224,11 +232,21 @@
</div> </div>
</section> </section>
<section id="account-preferences"> <section id="account-preferences">
<h2>Account &amp; preferences<a class="headerlink" href="#account-preferences" title="Permalink to this headline"></a></h2> <h2>Account &amp; preferences<a class="headerlink" href="#account-preferences" title="Permalink to this heading"></a></h2>
<ul class="simple">
<li><p>A user can create, update and deleted his account.</p></li>
<li><p>On registration, the user account is created with selected language in dropdown as user preference (<em>new in 0.6.9</em>).</p></li>
<li><p>After registration, the user account is inactive and an email with confirmation instructions is sent to activate it.
A user with an inactive account cannot log in. (<em>new in 0.6.0</em>)</p></li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>In case email sending is not configured, a <a class="reference external" href="cli.html#ftcli-users-update">command line</a> allows to activate users account.</p>
</div>
<ul class="simple"> <ul class="simple">
<li><p>A user can create, update and deleted his account</p></li>
<li><p>A user can set language, timezone and first day of week.</p></li> <li><p>A user can set language, timezone and first day of week.</p></li>
<li><p>A user can reset his password (<em>new in 0.3.0</em>)</p></li> <li><p>A user can reset his password (<em>new in 0.3.0</em>)</p></li>
<li><p>A user can change his email address (<em>new in 0.6.0</em>)</p></li>
<li><p>A user can choose between metric system and imperial system for distance, elevation and speed display (<em>new in 0.5.0</em>)</p></li> <li><p>A user can choose between metric system and imperial system for distance, elevation and speed display (<em>new in 0.5.0</em>)</p></li>
<li><dl class="simple"> <li><dl class="simple">
<dt>A user can set sport preferences (<em>new in 0.5.0</em>):</dt><dd><ul> <dt>A user can set sport preferences (<em>new in 0.5.0</em>):</dt><dd><ul>
@ -250,7 +268,7 @@
</div> </div>
</section> </section>
<section id="administration"> <section id="administration">
<h2>Administration<a class="headerlink" href="#administration" title="Permalink to this headline"></a></h2> <h2>Administration<a class="headerlink" href="#administration" title="Permalink to this heading"></a></h2>
<p>(<em>new in 0.3.0</em>)</p> <p>(<em>new in 0.3.0</em>)</p>
<ul> <ul>
<li><p><strong>Application</strong></p> <li><p><strong>Application</strong></p>
@ -260,16 +278,30 @@
<li><p>maximum size of uploaded files</p></li> <li><p>maximum size of uploaded files</p></li>
<li><p>maximum size of zip archive</p></li> <li><p>maximum size of zip archive</p></li>
<li><p>maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.</p></li> <li><p>maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.</p></li>
<li><p>administrator email for contact (<em>new in 0.6.0</em>)</p></li>
</ul> </ul>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<p>Updating server configuration may be necessary to handle large files (like <a class="reference external" href="https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size">nginx</a> for instance).</p> <p>Updating server configuration may be necessary to handle large files (like <a class="reference external" href="https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size">nginx</a> for instance).</p>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If email sending is disabled, a warning is displayed.</p>
</div>
</li> </li>
<li><p><strong>Users</strong></p> <li><p><strong>Users</strong></p>
<ul class="simple"> <ul class="simple">
<li><p>display users list and details</p></li> <li><p>display and filter users list</p></li>
<li><p>edit a user to add/remove administration rights</p></li> <li><dl class="simple">
<dt>edit a user to:</dt><dd><ul>
<li><p>add/remove administration rights</p></li>
<li><p>activate his account (<em>new in 0.6.0</em>)</p></li>
<li><p>update his email (in case his account is locked) (<em>new in 0.6.0</em>)</p></li>
<li><p>reset his password (in case his account is locked) (<em>new in 0.6.0</em>). If email sending is disabled, it is only possible via CLI.</p></li>
</ul>
</dd>
</dl>
</li>
<li><p>delete a user</p></li> <li><p>delete a user</p></li>
</ul> </ul>
</li> </li>
@ -281,37 +313,39 @@
</ul> </ul>
</section> </section>
<section id="translations"> <section id="translations">
<h2>Translations<a class="headerlink" href="#translations" title="Permalink to this headline"></a></h2> <h2>Translations<a class="headerlink" href="#translations" title="Permalink to this heading"></a></h2>
<p>FitTrackee is available in English and French (which can be saved in the user preferences).</p> <p>FitTrackee is available in the following languages (which can be saved in the user preferences):</p>
<figure class="align-default">
<img alt="https://hosted.weblate.org/widgets/fittrackee/-/multi-auto.svg" src="https://hosted.weblate.org/widgets/fittrackee/-/multi-auto.svg" /></figure>
</section> </section>
<section id="screenshots"> <section id="screenshots">
<h2>Screenshots<a class="headerlink" href="#screenshots" title="Permalink to this headline"></a></h2> <h2>Screenshots<a class="headerlink" href="#screenshots" title="Permalink to this heading"></a></h2>
<section id="dashboard"> <section id="dashboard">
<h3>Dashboard<a class="headerlink" href="#dashboard" title="Permalink to this headline"></a></h3> <h3>Dashboard<a class="headerlink" href="#dashboard" title="Permalink to this heading"></a></h3>
<figure class="align-default"> <figure class="align-default">
<img alt="FitTrackee Dashboard" src="_images/fittrackee_screenshot-01.png" /> <img alt="FitTrackee Dashboard" src="_images/fittrackee_screenshot-01.png" />
</figure> </figure>
</section> </section>
<section id="workout-detail"> <section id="workout-detail">
<h3>Workout detail<a class="headerlink" href="#workout-detail" title="Permalink to this headline"></a></h3> <h3>Workout detail<a class="headerlink" href="#workout-detail" title="Permalink to this heading"></a></h3>
<figure class="align-default"> <figure class="align-default">
<img alt="FitTrackee Workout" src="_images/fittrackee_screenshot-02.png" /> <img alt="FitTrackee Workout" src="_images/fittrackee_screenshot-02.png" />
</figure> </figure>
</section> </section>
<section id="workouts-list"> <section id="workouts-list">
<h3>Workouts list<a class="headerlink" href="#workouts-list" title="Permalink to this headline"></a></h3> <h3>Workouts list<a class="headerlink" href="#workouts-list" title="Permalink to this heading"></a></h3>
<figure class="align-default"> <figure class="align-default">
<img alt="FitTrackee Workouts" src="_images/fittrackee_screenshot-03.png" /> <img alt="FitTrackee Workouts" src="_images/fittrackee_screenshot-03.png" />
</figure> </figure>
</section> </section>
<section id="statistics"> <section id="statistics">
<h3>Statistics<a class="headerlink" href="#statistics" title="Permalink to this headline"></a></h3> <h3>Statistics<a class="headerlink" href="#statistics" title="Permalink to this heading"></a></h3>
<figure class="align-default"> <figure class="align-default">
<img alt="FitTrackee Statistics" src="_images/fittrackee_screenshot-04.png" /> <img alt="FitTrackee Statistics" src="_images/fittrackee_screenshot-04.png" />
</figure> </figure>
</section> </section>
<section id="id1"> <section id="id1">
<h3>Administration<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3> <h3>Administration<a class="headerlink" href="#id1" title="Permalink to this heading"></a></h3>
<figure class="align-default"> <figure class="align-default">
<img alt="FitTrackee Administration" src="_images/fittrackee_screenshot-05.png" /> <img alt="FitTrackee Administration" src="_images/fittrackee_screenshot-05.png" />
</figure> </figure>
@ -335,7 +369,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<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.5.7 <title>Index &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -12,6 +12,7 @@
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script> <script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script> <script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script> <script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="#" /> <link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
@ -37,7 +38,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -58,6 +59,7 @@
aria-labelledby="dLabelGlobalToc"><ul> aria-labelledby="dLabelGlobalToc"><ul>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -133,7 +135,7 @@
</li> </li>
<li><a href="installation.html#envvar-DATABASE_URL">DATABASE_URL</a> <li><a href="installation.html#envvar-DATABASE_URL">DATABASE_URL</a>
</li> </li>
<li><a href="installation.html#envvar-DEFAULT_STATICMAP">DEFAULT_STATICMAP 🆕</a> <li><a href="installation.html#envvar-DEFAULT_STATICMAP">DEFAULT_STATICMAP</a>
</li> </li>
<li><a href="installation.html#envvar-EMAIL_URL">EMAIL_URL</a> <li><a href="installation.html#envvar-EMAIL_URL">EMAIL_URL</a>
</li> </li>
@ -148,6 +150,8 @@
<li><a href="installation.html#envvar-REDIS_URL">REDIS_URL</a> <li><a href="installation.html#envvar-REDIS_URL">REDIS_URL</a>
</li> </li>
<li><a href="installation.html#envvar-SENDER_EMAIL">SENDER_EMAIL</a> <li><a href="installation.html#envvar-SENDER_EMAIL">SENDER_EMAIL</a>
</li>
<li><a href="installation.html#envvar-STATICMAP_SUBDOMAINS">STATICMAP_SUBDOMAINS 🆕</a>
</li> </li>
<li><a href="installation.html#envvar-TILE_SERVER_URL">TILE_SERVER_URL</a> <li><a href="installation.html#envvar-TILE_SERVER_URL">TILE_SERVER_URL</a>
</li> </li>
@ -179,7 +183,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<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.5.7 <title>HTTP Routing Table &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -12,6 +12,7 @@
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script> <script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script> <script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script> <script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
@ -44,7 +45,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -65,6 +66,7 @@
aria-labelledby="dLabelGlobalToc"><ul> aria-labelledby="dLabelGlobalToc"><ul>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -125,11 +127,6 @@
<tr class="pcap"><td></td><td>&#160;</td><td></td></tr> <tr class="pcap"><td></td><td>&#160;</td><td></td></tr>
<tr class="cap" id="cap-/api"><td></td><td> <tr class="cap" id="cap-/api"><td></td><td>
<strong>/api</strong></td><td></td></tr> <strong>/api</strong></td><td></td></tr>
<tr>
<td></td>
<td>
<a href="api/auth.html#get--api-auth-logout"><code class="xref">GET /api/auth/logout</code></a></td><td>
<em></em></td></tr>
<tr> <tr>
<td></td> <td></td>
<td> <td>
@ -235,6 +232,21 @@
<td> <td>
<a href="api/workouts.html#get--api-workouts-map_tile-(s)-(z)-(x)-(y).png"><code class="xref">GET /api/workouts/map_tile/(s)/(z)/(x)/(y).png</code></a></td><td> <a href="api/workouts.html#get--api-workouts-map_tile-(s)-(z)-(x)-(y).png"><code class="xref">GET /api/workouts/map_tile/(s)/(z)/(x)/(y).png</code></a></td><td>
<em></em></td></tr> <em></em></td></tr>
<tr>
<td></td>
<td>
<a href="api/auth.html#post--api-auth-account-confirm"><code class="xref">POST /api/auth/account/confirm</code></a></td><td>
<em></em></td></tr>
<tr>
<td></td>
<td>
<a href="api/auth.html#post--api-auth-account-resend-confirmation"><code class="xref">POST /api/auth/account/resend-confirmation</code></a></td><td>
<em></em></td></tr>
<tr>
<td></td>
<td>
<a href="api/auth.html#post--api-auth-email-update"><code class="xref">POST /api/auth/email/update</code></a></td><td>
<em></em></td></tr>
<tr> <tr>
<td></td> <td></td>
<td> <td>
@ -305,6 +317,11 @@
<td> <td>
<a href="api/workouts.html#delete--api-workouts-(string-workout_short_id)"><code class="xref">DELETE /api/workouts/(string:workout_short_id)</code></a></td><td> <a href="api/workouts.html#delete--api-workouts-(string-workout_short_id)"><code class="xref">DELETE /api/workouts/(string:workout_short_id)</code></a></td><td>
<em></em></td></tr> <em></em></td></tr>
<tr>
<td></td>
<td>
<a href="api/auth.html#patch--api-auth-profile-edit-account"><code class="xref">PATCH /api/auth/profile/edit/account</code></a></td><td>
<em></em></td></tr>
<tr> <tr>
<td></td> <td></td>
<td> <td>
@ -340,7 +357,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>FitTrackee &#8212; FitTrackee 0.5.7 <title>FitTrackee &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script> <script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script> <script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script> <script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
@ -39,7 +40,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -60,6 +61,7 @@
aria-labelledby="dLabelGlobalToc"><ul> aria-labelledby="dLabelGlobalToc"><ul>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -122,7 +124,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="fittrackee"> <section id="fittrackee">
<h1>FitTrackee<a class="headerlink" href="#fittrackee" title="Permalink to this headline"></a></h1> <h1>FitTrackee<a class="headerlink" href="#fittrackee" title="Permalink to this heading"></a></h1>
<div class="line-block"> <div class="line-block">
<div class="line">This web application allows you to track your outdoor activities (workouts) <div class="line">This web application allows you to track your outdoor activities (workouts)
from gpx files and keep your data on your own server.</div> from gpx files and keep your data on your own server.</div>
@ -148,11 +150,12 @@ Map</a>.</div>
</figure> </figure>
</section> </section>
<section id="table-of-contents"> <section id="table-of-contents">
<h1>Table of contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline"></a></h1> <h1>Table of contents<a class="headerlink" href="#table-of-contents" title="Permalink to this heading"></a></h1>
<div class="toctree-wrapper compound"> <div class="toctree-wrapper compound">
<ul> <ul>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -173,7 +176,7 @@ Map</a>.</div>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Installation &#8212; FitTrackee 0.5.7 <title>Installation &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -13,10 +13,11 @@
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script> <script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script> <script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script> <script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
<link rel="next" title="API documentation" href="api/index.html" /> <link rel="next" title="Command line interface" href="cli.html" />
<link rel="prev" title="Features" href="features.html" /> <link rel="prev" title="Features" href="features.html" />
<meta charset='utf-8'> <meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'> <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Installation</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -123,7 +125,7 @@
</a> </a>
</li> </li>
<li> <li>
<a href="api/index.html" title="Next Chapter: API documentation"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">API documentation &raquo;</span> <a href="cli.html" title="Next Chapter: Command line interface"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Command line ... &raquo;</span>
</a> </a>
</li> </li>
@ -158,7 +160,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="installation"> <section id="installation">
<h1>Installation<a class="headerlink" href="#installation" title="Permalink to this headline"></a></h1> <h1>Installation<a class="headerlink" href="#installation" title="Permalink to this heading"></a></h1>
<p>This application is written in Python (API) and Typescript (client):</p> <p>This application is written in Python (API) and Typescript (client):</p>
<ul class="simple"> <ul class="simple">
<li><dl class="simple"> <li><dl class="simple">
@ -182,16 +184,18 @@
</dl> </dl>
</li> </li>
</ul> </ul>
<p>Logo, sports and weather icons are made by <a class="reference external" href="https://www.freepik.com/">Freepik</a> from <a class="reference external" href="https://www.flaticon.com/">www.flaticon.com</a>.</p> <div class="line-block">
<div class="line">Logo, some sports and weather icons are made by <a class="reference external" href="https://www.freepik.com/">Freepik</a> from <a class="reference external" href="https://www.flaticon.com/">www.flaticon.com</a>.</div>
<div class="line">FitTrackee also uses icons from <a class="reference external" href="https://forkaweso.me">Fork Awesome</a>.</div>
</div>
<section id="prerequisites"> <section id="prerequisites">
<h2>Prerequisites<a class="headerlink" href="#prerequisites" title="Permalink to this headline"></a></h2> <h2>Prerequisites<a class="headerlink" href="#prerequisites" title="Permalink to this heading"></a></h2>
<ul class="simple"> <ul class="simple">
<li><p>PostgreSQL database (10+)</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>PostgreSQL database (10+)</p></li>
<li><p>SMTP provider and Redis for task queue (if email sending is enabled)</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><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://poetry.eustace.io">Poetry</a> (for installation from sources only)</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><a class="reference external" href="https://yarnpkg.com">Yarn</a> (for development only)</p></li> <li><p><a class="reference external" href="https://yarnpkg.com">Yarn</a> (for development only)</p></li>
<li><p>Docker and Docker Compose (for development or evaluation purposes)</p></li> <li><p>Docker and Docker Compose (for development or evaluation purposes)</p></li>
</ul> </ul>
@ -206,7 +210,7 @@ necessary.</div>
</div> </div>
</section> </section>
<section id="environment-variables"> <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 heading"></a></h2>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<div class="line-block"> <div class="line-block">
@ -230,7 +234,7 @@ deployment method.</p>
<span class="sig-name descname"><span class="pre">HOST</span></span><a class="headerlink" href="#envvar-HOST" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">HOST</span></span><a class="headerlink" href="#envvar-HOST" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> host.</p> <dd><p><strong>FitTrackee</strong> host.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>0.0.0.0</p> <dd class="field-odd"><p>0.0.0.0</p>
</dd> </dd>
</dl> </dl>
@ -241,7 +245,7 @@ deployment method.</p>
<span class="sig-name descname"><span class="pre">PORT</span></span><a class="headerlink" href="#envvar-PORT" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">PORT</span></span><a class="headerlink" href="#envvar-PORT" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> port.</p> <dd><p><strong>FitTrackee</strong> port.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>5000</p> <dd class="field-odd"><p>5000</p>
</dd> </dd>
</dl> </dl>
@ -252,7 +256,7 @@ deployment method.</p>
<span class="sig-name descname"><span class="pre">APP_SETTINGS</span></span><a class="headerlink" href="#envvar-APP_SETTINGS" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">APP_SETTINGS</span></span><a class="headerlink" href="#envvar-APP_SETTINGS" title="Permalink to this definition"></a></dt>
<dd><p><strong>FitTrackee</strong> configuration.</p> <dd><p><strong>FitTrackee</strong> configuration.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>fittrackee.config.ProductionConfig</p> <dd class="field-odd"><p>fittrackee.config.ProductionConfig</p>
</dd> </dd>
</dl> </dl>
@ -269,7 +273,7 @@ deployment method.</p>
<span class="sig-name descname"><span class="pre">APP_WORKERS</span></span><a class="headerlink" href="#envvar-APP_WORKERS" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">APP_WORKERS</span></span><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> <dd><p>Number of workers spawned by <strong>Gunicorn</strong>.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>1</p> <dd class="field-odd"><p>1</p>
</dd> </dd>
</dl> </dl>
@ -290,10 +294,10 @@ deployment method.</p>
<dd><div class="versionadded"> <dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p> <p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div> </div>
<p>Directory containing uploaded files.</p> <p><strong>Absolute path</strong> to the directory where <cite>uploads</cite> folder will be created.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p><cite>fittrackee/uploads/</cite></p> <dd class="field-odd"><p><cite>&lt;application_directory&gt;/fittrackee</cite></p>
</dd> </dd>
</dl> </dl>
<div class="admonition danger"> <div class="admonition danger">
@ -312,8 +316,8 @@ deployment method.</p>
<div class="line">Database URL with username and password, must be initialized in production environment.</div> <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">postgresql://fittrackee:fittrackee&#64;localhost:5432/fittrackee</span></code></div> <div class="line">For example in dev environment : <code class="docutils literal notranslate"><span class="pre">postgresql://fittrackee:fittrackee&#64;localhost:5432/fittrackee</span></code></div>
</div> </div>
<div class="admonition danger"> <div class="admonition warning">
<p class="admonition-title">Danger</p> <p class="admonition-title">Warning</p>
<div class="line-block"> <div class="line-block">
<div class="line">Since <a class="reference external" href="https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b">SQLAlchemy update (1.4+)</a>, <div class="line">Since <a class="reference external" href="https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b">SQLAlchemy update (1.4+)</a>,
engine URL should begin with <cite>postgresql://</cite>.</div> engine URL should begin with <cite>postgresql://</cite>.</div>
@ -330,7 +334,7 @@ engine URL should begin with <cite>postgresql://</cite>.</div>
<p>Disable pooling if needed (when starting application with <strong>FitTrackee</strong> entry point and not directly with <strong>Gunicorn</strong>), <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> 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"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>false</p> <dd class="field-odd"><p>false</p>
</dd> </dd>
</dl> </dl>
@ -349,6 +353,18 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
<p><span class="versionmodified added">New in version 0.3.0.</span></p> <p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div> </div>
<p>Email URL with credentials, see <a class="reference external" href="installation.html#emails">Emails</a>.</p> <p>Email URL with credentials, see <a class="reference external" href="installation.html#emails">Emails</a>.</p>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.6.5.</span></p>
</div>
<dl class="field-list simple">
<dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>empty string</p>
</dd>
</dl>
<div class="admonition danger">
<p class="admonition-title">Danger</p>
<p>If the email URL is empty, email sending will be disabled.</p>
</div>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<p>If the email URL is invalid, the application may not start.</p> <p>If the email URL is invalid, the application may not start.</p>
@ -372,7 +388,7 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
</div> </div>
<p>Redis instance used by <strong>Dramatiq</strong>.</p> <p>Redis instance used by <strong>Dramatiq</strong>.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>local Redis instance (<code class="docutils literal notranslate"><span class="pre">redis://</span></code>)</p> <dd class="field-odd"><p>local Redis instance (<code class="docutils literal notranslate"><span class="pre">redis://</span></code>)</p>
</dd> </dd>
</dl> </dl>
@ -398,12 +414,29 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
<div class="line">Since <strong>0.4.9</strong>, its also used to generate static maps (to keep default server, see <a class="reference external" href="installation.html#envvar-DEFAULT_STATICMAP">DEFAULT_STATICMAP</a>)</div> <div class="line">Since <strong>0.4.9</strong>, its also used to generate static maps (to keep default server, see <a class="reference external" href="installation.html#envvar-DEFAULT_STATICMAP">DEFAULT_STATICMAP</a>)</div>
</div> </div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p><cite>https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png</cite></p> <dd class="field-odd"><p><cite>https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png</cite></p>
</dd> </dd>
</dl> </dl>
</dd></dl> </dd></dl>
<dl class="std envvar">
<dt class="sig sig-object std" id="envvar-STATICMAP_SUBDOMAINS">
<span class="sig-name descname"><span class="pre">STATICMAP_SUBDOMAINS</span> <span class="pre">🆕</span></span><a class="headerlink" href="#envvar-STATICMAP_SUBDOMAINS" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.6.10.</span></p>
</div>
<div class="line-block">
<div class="line">Some tile servers require a subdomain, see <a class="reference external" href="installation.html#map-tile-server">Map tile server</a>.</div>
<div class="line">For instance: “a,b,c” for OSM France.</div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>empty string</p>
</dd>
</dl>
</dd></dl>
<dl class="std envvar"> <dl class="std envvar">
<dt class="sig sig-object std" id="envvar-MAP_ATTRIBUTION"> <dt class="sig sig-object std" id="envvar-MAP_ATTRIBUTION">
<span class="sig-name descname"><span class="pre">MAP_ATTRIBUTION</span></span><a class="headerlink" href="#envvar-MAP_ATTRIBUTION" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">MAP_ATTRIBUTION</span></span><a class="headerlink" href="#envvar-MAP_ATTRIBUTION" title="Permalink to this definition"></a></dt>
@ -412,7 +445,7 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
</div> </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> <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"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></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 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> </dd>
</dl> </dl>
@ -420,13 +453,23 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
<dl class="std envvar"> <dl class="std envvar">
<dt class="sig sig-object std" id="envvar-DEFAULT_STATICMAP"> <dt class="sig sig-object std" id="envvar-DEFAULT_STATICMAP">
<span id="envvar-DEFAULT_STATICMAP 🆕"></span><span class="sig-name descname"><span class="pre">DEFAULT_STATICMAP</span> <span class="pre">🆕</span></span><a class="headerlink" href="#envvar-DEFAULT_STATICMAP" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">DEFAULT_STATICMAP</span></span><a class="headerlink" href="#envvar-DEFAULT_STATICMAP" title="Permalink to this definition"></a></dt>
<dd><div class="versionadded"> <dd><div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.9.</span></p> <p><span class="versionmodified added">New in version 0.4.9.</span></p>
</div> </div>
<p>If <cite>True</cite>, it keeps using default tile server to generate static maps.</p> <div class="line-block">
<div class="line">If <cite>True</cite>, it keeps using default tile server to generate static maps (Komoot.de tile server).</div>
<div class="line">Otherwise, it uses the tile server set in <a class="reference external" href="installation.html#envvar-TILE_SERVER_URL">TILE_SERVER_URL</a>.</div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.6.10.</span></p>
</div>
<div class="line-block">
<div class="line">This variable is now case-insensitive.</div>
<div class="line">If <cite>False</cite>, depending on tile server, <a class="reference external" href="installation.html#envvar-STATICMAP_SUBDOMAINS">subdomains</a> may be mandatory.</div>
</div>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Default</dt> <dt class="field-odd">Default<span class="colon">:</span></dt>
<dd class="field-odd"><p>False</p> <dd class="field-odd"><p>False</p>
</dd> </dd>
</dl> </dl>
@ -448,7 +491,7 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
</dd></dl> </dd></dl>
<section id="emails"> <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 heading"></a></h3>
<div class="versionadded"> <div class="versionadded">
<p><span class="versionmodified added">New in version 0.3.0.</span></p> <p><span class="versionmodified added">New in version 0.3.0.</span></p>
</div> </div>
@ -458,16 +501,43 @@ see <a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/p
<li><p>with SSL: <code class="docutils literal notranslate"><span class="pre">smtp://username:password&#64;smtp.example.com:465/?ssl=True</span></code></p></li> <li><p>with SSL: <code class="docutils literal notranslate"><span class="pre">smtp://username:password&#64;smtp.example.com:465/?ssl=True</span></code></p></li>
<li><p>with STARTTLS: <code class="docutils literal notranslate"><span class="pre">smtp://username:password&#64;smtp.example.com:587/?tls=True</span></code></p></li> <li><p>with STARTTLS: <code class="docutils literal notranslate"><span class="pre">smtp://username:password&#64;smtp.example.com:587/?tls=True</span></code></p></li>
</ul> </ul>
<div class="versionadded"> <div class="admonition warning">
<p><span class="versionmodified added">New in version 0.5.3.</span></p> <p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">- If the email URL is invalid, the application may not start.</div>
<div class="line">- Sending emails with Office365 may not work if SMTP auth is disabled.</div>
</div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.5.3.</span></p>
</div> </div>
<div class="line-block"> <div class="line-block">
<div class="line">Credentials can be omitted: <code class="docutils literal notranslate"><span class="pre">smtp://smtp.example.com:25</span></code>.</div> <div class="line">Credentials can be omitted: <code class="docutils literal notranslate"><span class="pre">smtp://smtp.example.com:25</span></code>.</div>
<div class="line">If <code class="docutils literal notranslate"><span class="pre">:&lt;port&gt;</span></code> is omitted, the port defaults to 25.</div> <div class="line">If <code class="docutils literal notranslate"><span class="pre">:&lt;port&gt;</span></code> is omitted, the port defaults to 25.</div>
</div> </div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="line-block">
<div class="line">Since 0.6.0, newly created accounts must be confirmed (an email with confirmation instructions is sent after registration).</div>
</div>
</div>
<p>Emails sent by FitTrackee are:</p>
<ul class="simple">
<li><p>account confirmation instructions</p></li>
<li><p>password reset request</p></li>
<li><p>email change (to old and new email adresses)</p></li>
<li><p>password change</p></li>
</ul>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.6.5.</span></p>
</div>
<div class="line-block">
<div class="line">For single-user instance, it is possible to disable email sending with an empty <code class="docutils literal notranslate"><span class="pre">EMAIL_URL</span></code> (in this case, no need to start dramatiq workers).</div>
<div class="line">A <a class="reference external" href="cli.html#ftcli-users-update">CLI</a> is available to activate account and modify email and password.</div>
</div>
</section> </section>
<section id="map-tile-server"> <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 heading"></a></h3>
<div class="versionadded"> <div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.0.</span></p> <p><span class="versionmodified added">New in version 0.4.0.</span></p>
</div> </div>
@ -484,10 +554,21 @@ The tile server can be changed by updating <code class="docutils literal notrans
<div class="line">Check the terms of service of tile provider for map attribution</div> <div class="line">Check the terms of service of tile provider for map attribution</div>
</div> </div>
</div> </div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.6.10.</span></p>
</div>
<p>Since the tile server can be used for static map generation, some servers require a subdomain.</p>
<p>For instance, to set OSM France tile server, the expected values are:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">TILE_SERVER_URL=https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">MAP_ATTRIBUTION='fond</span> <span class="pre">de</span> <span class="pre">carte</span> <span class="pre">par</span> <span class="pre">&lt;a</span> <span class="pre">href=&quot;http://www.openstreetmap.fr/mentions-legales/&quot;</span> <span class="pre">target=&quot;_blank&quot;</span> <span class="pre">rel=&quot;nofollow</span> <span class="pre">noopener&quot;&gt;OpenStreetMap</span> <span class="pre">France&lt;/a&gt;,</span> <span class="pre">sous&amp;nbsp;&lt;a</span> <span class="pre">href=&quot;http://creativecommons.org/licenses/by-sa/2.0/fr/&quot;</span> <span class="pre">target=&quot;_blank&quot;</span> <span class="pre">rel=&quot;nofollow</span> <span class="pre">noopener&quot;&gt;licence</span> <span class="pre">CC</span> <span class="pre">BY-SA&lt;/a&gt;'</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">STATICMAP_SUBDOMAINS=a,b,c</span></code></p></li>
</ul>
<p>The subdomain will be chosen randomly.</p>
</section> </section>
</section> </section>
<section id="id1"> <section id="id1">
<h2>Installation<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h2> <h2>Installation<a class="headerlink" href="#id1" title="Permalink to this heading"></a></h2>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<div class="line-block"> <div class="line-block">
@ -495,7 +576,7 @@ The tile server can be changed by updating <code class="docutils literal notrans
</div> </div>
</div> </div>
<section id="from-pypi"> <section id="from-pypi">
<h3>From PyPI<a class="headerlink" href="#from-pypi" title="Permalink to this headline"></a></h3> <h3>From PyPI<a class="headerlink" href="#from-pypi" title="Permalink to this heading"></a></h3>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Note</p> <p class="admonition-title">Note</p>
<div class="line-block"> <div class="line-block">
@ -529,7 +610,7 @@ $ <span class="nb">source</span> .env
<ul class="simple"> <ul class="simple">
<li><p>Initialize database schema</p></li> <li><p>Initialize database schema</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_upgrade_db <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ ftcli db upgrade
</pre></div> </pre></div>
</div> </div>
<ul class="simple"> <ul class="simple">
@ -539,7 +620,7 @@ $ <span class="nb">source</span> .env
</pre></div> </pre></div>
</div> </div>
<ul class="simple"> <ul class="simple">
<li><p>Start task queue workers</p></li> <li><p>Start task queue workers if email sending is enabled.</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_worker --processes <span class="m">2</span> <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_worker --processes <span class="m">2</span>
</pre></div> </pre></div>
@ -552,14 +633,18 @@ $ <span class="nb">source</span> .env
</div> </div>
<ul class="simple"> <ul class="simple">
<li><p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a> and register</p></li> <li><p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a> and register</p></li>
<li><p>To set admin rights to the newly created account, use the following command:</p></li> <li><p>To set admin rights to the newly created account, use the following command line:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_set_admin &lt;username&gt; <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ ftcli users update &lt;username&gt; --set-admin <span class="nb">true</span>
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If the user account is inactive, it activates it.</p>
</div>
</section> </section>
<section id="from-sources"> <section id="from-sources">
<h3>From sources<a class="headerlink" href="#from-sources" title="Permalink to this headline"></a></h3> <h3>From sources<a class="headerlink" href="#from-sources" title="Permalink to this heading"></a></h3>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<div class="line-block"> <div class="line-block">
@ -577,7 +662,7 @@ $ poetry config virtualenvs.in-project <span class="nb">true</span>
<p>For other OS, see <a class="reference external" href="https://python-poetry.org/docs/#installation">Poetry Documentation</a></p> <p>For other OS, see <a class="reference external" href="https://python-poetry.org/docs/#installation">Poetry Documentation</a></p>
</div> </div>
<section id="dev-environment"> <section id="dev-environment">
<h4>Dev environment<a class="headerlink" href="#dev-environment" title="Permalink to this headline"></a></h4> <h4>Dev environment<a class="headerlink" href="#dev-environment" title="Permalink to this heading"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p>Clone this repo:</p></li> <li><p>Clone this repo:</p></li>
</ul> </ul>
@ -609,14 +694,18 @@ $ make install-db
</div> </div>
<ul class="simple"> <ul class="simple">
<li><p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a> and register</p></li> <li><p>Open <a class="reference external" href="http://localhost:3000">http://localhost:3000</a> and register</p></li>
<li><p>To set admin rights to the newly created account, use the following command:</p></li> <li><p>To set admin rights to the newly created account, use the following command line:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make set-admin <span class="nv">USERNAME</span><span class="o">=</span>&lt;username&gt; <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make user-set-admin <span class="nv">USERNAME</span><span class="o">=</span>&lt;username&gt;
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If the user account is inactive, it activates it.</p>
</div>
</section> </section>
<section id="production-environment"> <section id="production-environment">
<h4>Production environment<a class="headerlink" href="#production-environment" title="Permalink to this headline"></a></h4> <h4>Production environment<a class="headerlink" href="#production-environment" title="Permalink to this heading"></a></h4>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<div class="line-block"> <div class="line-block">
@ -624,11 +713,11 @@ $ make install-db
</div> </div>
</div> </div>
<ul class="simple"> <ul class="simple">
<li><p>Download the last release (for now, it is the release v0.5.7):</p></li> <li><p>Download the last release (for now, it is the release v0.6.10):</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.5.7.tar.gz <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.10.tar.gz
$ tar -xzf v0.5.7.tar.gz $ tar -xzf v0.6.10.tar.gz
$ mv FitTrackee-0.5.7 FitTrackee $ mv FitTrackee-0.6.10 FitTrackee
$ <span class="nb">cd</span> FitTrackee $ <span class="nb">cd</span> FitTrackee
</pre></div> </pre></div>
</div> </div>
@ -653,18 +742,26 @@ database credentials</strong>):</p></li>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If email sending is disabled: <code class="docutils literal notranslate"><span class="pre">$</span> <span class="pre">make</span> <span class="pre">run-server</span></code></p>
</div>
<ul class="simple"> <ul class="simple">
<li><p>Open <a class="reference external" href="http://localhost:5000">http://localhost:5000</a> and register</p></li> <li><p>Open <a class="reference external" href="http://localhost:5000">http://localhost:5000</a> and register</p></li>
<li><p>To set admin rights to the newly created account, use the following command:</p></li> <li><p>To set admin rights to the newly created account, use the following command line:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make set-admin <span class="nv">USERNAME</span><span class="o">=</span>&lt;username&gt; <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make user-set-admin <span class="nv">USERNAME</span><span class="o">=</span>&lt;username&gt;
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If the user account is inactive, it activates it.</p>
</div>
</section> </section>
</section> </section>
</section> </section>
<section id="upgrade"> <section id="upgrade">
<h2>Upgrade<a class="headerlink" href="#upgrade" title="Permalink to this headline"></a></h2> <h2>Upgrade<a class="headerlink" href="#upgrade" title="Permalink to this heading"></a></h2>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Warning</p> <p class="admonition-title">Warning</p>
<div class="line-block"> <div class="line-block">
@ -674,9 +771,9 @@ database credentials</strong>):</p></li>
</div> </div>
</div> </div>
<section id="id2"> <section id="id2">
<h3>From PyPI<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3> <h3>From PyPI<a class="headerlink" href="#id2" title="Permalink to this heading"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p>Activate the virtualenv</p></li> <li><p>Stop the application and activate the virtualenv</p></li>
<li><p>Upgrade with pip</p></li> <li><p>Upgrade with pip</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ pip install -U fittrackee <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ pip install -U fittrackee
@ -692,17 +789,17 @@ $ <span class="nb">source</span> .env
<ul class="simple"> <ul class="simple">
<li><p>Upgrade database if needed (see changelog for migrations):</p></li> <li><p>Upgrade database if needed (see changelog for migrations):</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ fittrackee_upgrade_db <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ ftcli db upgrade
</pre></div> </pre></div>
</div> </div>
<ul class="simple"> <ul class="simple">
<li><p>Restart the application and task queue workers.</p></li> <li><p>Restart the application and task queue workers (if email sending is enabled).</p></li>
</ul> </ul>
</section> </section>
<section id="id3"> <section id="id3">
<h3>From sources<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3> <h3>From sources<a class="headerlink" href="#id3" title="Permalink to this heading"></a></h3>
<section id="id4"> <section id="id4">
<h4>Dev environment<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h4> <h4>Dev environment<a class="headerlink" href="#id4" title="Permalink to this heading"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p>Stop the application and pull the repository:</p></li> <li><p>Stop the application and pull the repository:</p></li>
</ul> </ul>
@ -736,15 +833,15 @@ $ <span class="nb">source</span> .env
</div> </div>
</section> </section>
<section id="prod-environment"> <section id="prod-environment">
<h4>Prod environment<a class="headerlink" href="#prod-environment" title="Permalink to this headline"></a></h4> <h4>Prod environment<a class="headerlink" href="#prod-environment" title="Permalink to this heading"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p>Stop the application</p></li> <li><p>Stop the application</p></li>
<li><p>Change to the directory where FitTrackee directory is located</p></li> <li><p>Change to the directory where FitTrackee directory is located</p></li>
<li><p>Download the last release (for now, it is the release v0.5.7) and overwrite existing files:</p></li> <li><p>Download the last release (for now, it is the release v0.6.10) and overwrite existing files:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.5.7.tar.gz <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.10.tar.gz
$ tar -xzf v0.5.7.tar.gz $ tar -xzf v0.6.10.tar.gz
$ cp -R FitTrackee-0.5.7/* FitTrackee/ $ cp -R FitTrackee-0.6.10/* FitTrackee/
$ <span class="nb">cd</span> FitTrackee $ <span class="nb">cd</span> FitTrackee
</pre></div> </pre></div>
</div> </div>
@ -767,11 +864,15 @@ $ <span class="nb">cd</span> FitTrackee
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make run
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If email sending is disabled: <code class="docutils literal notranslate"><span class="pre">$</span> <span class="pre">make</span> <span class="pre">run-server</span></code></p>
</div>
</section> </section>
</section> </section>
</section> </section>
<section id="deployment"> <section id="deployment">
<h2>Deployment<a class="headerlink" href="#deployment" title="Permalink to this headline"></a></h2> <h2>Deployment<a class="headerlink" href="#deployment" title="Permalink to this heading"></a></h2>
<p>There are several ways to start <strong>FitTrackee</strong> web application and task queue <p>There are several ways to start <strong>FitTrackee</strong> web application and task queue
library. library.
One way is to use a <strong>systemd</strong> services and <strong>Nginx</strong> to proxy pass to <strong>Gunicorn</strong>.</p> One way is to use a <strong>systemd</strong> services and <strong>Nginx</strong> to proxy pass to <strong>Gunicorn</strong>.</p>
@ -803,6 +904,7 @@ One way is to use a <strong>systemd</strong> services and <strong>Nginx</strong>
<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;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;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;TILE_SERVER_URL=&quot;</span>
<span class="n">Environment</span><span class="o">=</span><span class="s2">&quot;STATICMAP_SUBDOMAINS=&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;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">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">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>
@ -886,30 +988,34 @@ server {
</div> </div>
</section> </section>
<section id="docker"> <section id="docker">
<h2>Docker<a class="headerlink" href="#docker" title="Permalink to this headline"></a></h2> <h2>Docker<a class="headerlink" href="#docker" title="Permalink to this heading"></a></h2>
<section id="id5"> <section id="id5">
<h3>Installation<a class="headerlink" href="#id5" title="Permalink to this headline"></a></h3> <h3>Installation<a class="headerlink" href="#id5" title="Permalink to this heading"></a></h3>
<div class="versionadded"> <div class="versionadded">
<p><span class="versionmodified added">New in version 0.4.4.</span></p> <p><span class="versionmodified added">New in version 0.4.4.</span></p>
</div> </div>
<p>For evaluation purposes , docker files are available, <p>For evaluation purposes, docker files are available, installing <strong>FitTrackee</strong> from <strong>sources</strong>.</p>
installing <strong>FitTrackee</strong> from <strong>sources</strong>.</p>
<ul class="simple"> <ul class="simple">
<li><p>To install <strong>FitTrackee</strong> with database initialisation and run the application and dramatiq workers:</p></li> <li><p>To install <strong>FitTrackee</strong> with database initialisation and run the application and dramatiq workers:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ git clone https://github.com/SamR1/FitTrackee.git <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 $ <span class="nb">cd</span> FitTrackee
$ cp .env.docker .env
$ make docker-build docker-run docker-init $ make docker-build docker-run docker-init
</pre></div> </pre></div>
</div> </div>
<p>Open <a class="reference external" href="http://localhost:5000">http://localhost:5000</a> and register.</p> <p>Open <a class="reference external" href="http://localhost:5000">http://localhost:5000</a> and register.</p>
<p>Open <a class="reference external" href="http://localhost:8025">http://localhost:8025</a> to access <a class="reference external" href="https://github.com/mailhog/MailHog">MailHog interface</a> (email testing tool)</p> <p>Open <a class="reference external" href="http://localhost:8025">http://localhost:8025</a> to access <a class="reference external" href="https://github.com/mailhog/MailHog">MailHog interface</a> (email testing tool)</p>
<ul class="simple"> <ul class="simple">
<li><p>To set admin rights to the newly created account, use the following command:</p></li> <li><p>To set admin rights to the newly created account, use the following command line:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make docker-set-admin <span class="nv">USERNAME</span><span class="o">=</span>&lt;username&gt; <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ make docker-set-admin <span class="nv">USERNAME</span><span class="o">=</span>&lt;username&gt;
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If the user account is inactive, it activates it.</p>
</div>
<ul class="simple"> <ul class="simple">
<li><p>To stop <strong>Fittrackee</strong>:</p></li> <li><p>To stop <strong>Fittrackee</strong>:</p></li>
</ul> </ul>
@ -930,7 +1036,7 @@ $ make docker-build docker-run docker-init
</div> </div>
</section> </section>
<section id="development"> <section id="development">
<h3>Development<a class="headerlink" href="#development" title="Permalink to this headline"></a></h3> <h3>Development<a class="headerlink" href="#development" title="Permalink to this heading"></a></h3>
<div class="versionadded"> <div class="versionadded">
<p><span class="versionmodified added">New in version 0.5.0.</span></p> <p><span class="versionmodified added">New in version 0.5.0.</span></p>
</div> </div>
@ -968,7 +1074,7 @@ $ make docker-build docker-run docker-init
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

Binary file not shown.

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<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.5.7 <title>Search &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -12,6 +12,7 @@
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script> <script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script> <script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script> <script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" /> <link rel="search" title="Search" href="#" />
@ -44,7 +45,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -65,6 +66,7 @@
aria-labelledby="dLabelGlobalToc"><ul> aria-labelledby="dLabelGlobalToc"><ul>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="api/index.html">API documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="troubleshooting/index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a></li>
@ -149,7 +151,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Administrator &#8212; FitTrackee 0.5.7 <title>Administrator &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="../api/index.html">API documentation</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Troubleshooting</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -79,6 +81,7 @@
aria-labelledby="dLabelLocalToc"><ul> aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Administrator</a><ul> <li><a class="reference internal" href="#">Administrator</a><ul>
<li><a class="reference internal" href="#fittrackee-fails-to-start"><cite>FitTrackee fails to start</cite></a></li> <li><a class="reference internal" href="#fittrackee-fails-to-start"><cite>FitTrackee fails to start</cite></a></li>
<li><a class="reference internal" href="#map-images-are-not-displayed-but-map-is-shown-in-workout-detail"><cite>Map images are not displayed but map is shown in Workout detail</cite></a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -129,16 +132,29 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="administrator"> <section id="administrator">
<h1>Administrator<a class="headerlink" href="#administrator" title="Permalink to this headline"></a></h1> <h1>Administrator<a class="headerlink" href="#administrator" title="Permalink to this heading"></a></h1>
<section id="fittrackee-fails-to-start"> <section id="fittrackee-fails-to-start">
<h2><cite>FitTrackee fails to start</cite><a class="headerlink" href="#fittrackee-fails-to-start" title="Permalink to this headline"></a></h2> <h2><cite>FitTrackee fails to start</cite><a class="headerlink" href="#fittrackee-fails-to-start" title="Permalink to this heading"></a></h2>
<ul class="simple"> <ul>
<li><p>Check the database URL in <a class="reference external" href="../installation.html#envvar-DATABASE_URL">Environment variables</a> if the following error is displayed in <strong>gunicorn</strong> logs:</p></li> <li><p>Check the database URL in <a class="reference external" href="../installation.html#envvar-DATABASE_URL">environment variables</a> if the following error is displayed in <strong>gunicorn</strong> logs:</p>
</ul>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sqlalchemy</span><span class="o">.</span><span class="n">exc</span><span class="o">.</span><span class="n">NoSuchModuleError</span><span class="p">:</span> <span class="n">Can</span><span class="s1">&#39;t load plugin: sqlalchemy.dialects:postgres</span> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sqlalchemy</span><span class="o">.</span><span class="n">exc</span><span class="o">.</span><span class="n">NoSuchModuleError</span><span class="p">:</span> <span class="n">Can</span><span class="s1">&#39;t load plugin: sqlalchemy.dialects:postgres</span>
</pre></div> </pre></div>
</div> </div>
<p>It must start with <cite>postgresql://</cite> (engine URLs starting with <cite>postgres://</cite> are no longer supported).</p> <p>It must start with <cite>postgresql://</cite> (engine URLs starting with <cite>postgres://</cite> are no longer supported).</p>
</li>
<li><p>Check the email URL in <a class="reference external" href="../installation.html#envvar-EMAIL_URL">environment variables</a> if the following error is displayed in <strong>gunicorn</strong> logs:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">fittrackee</span><span class="o">.</span><span class="n">emails</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">InvalidEmailUrlScheme</span>
</pre></div>
</div>
<p>A valid <code class="docutils literal notranslate"><span class="pre">EMAIL_URL</span></code> must be provided (see <a class="reference external" href="../installation.html#emails">emails</a>).</p>
</li>
</ul>
</section>
<section id="map-images-are-not-displayed-but-map-is-shown-in-workout-detail">
<h2><cite>Map images are not displayed but map is shown in Workout detail</cite><a class="headerlink" href="#map-images-are-not-displayed-but-map-is-shown-in-workout-detail" title="Permalink to this heading"></a></h2>
<ul class="simple">
<li><p>Check the path in <a class="reference external" href="../installation.html#envvar-UPLOAD_FOLDER">environment variables</a>. <code class="docutils literal notranslate"><span class="pre">UPLOAD_FOLDER</span></code> must be set with an absolute path.</p></li>
</ul>
</section> </section>
</section> </section>
@ -155,7 +171,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>Troubleshooting &#8212; FitTrackee 0.5.7 <title>Troubleshooting &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="../api/index.html">API documentation</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Troubleshooting</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,12 +128,12 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="troubleshooting"> <section id="troubleshooting">
<h1>Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permalink to this headline"></a></h1> <h1>Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permalink to this heading"></a></h1>
<div class="toctree-wrapper compound"> <div class="toctree-wrapper compound">
<p class="caption" role="heading"><span class="caption-text">Endpoints:</span></p>
<ul> <ul>
<li class="toctree-l1"><a class="reference internal" href="administrator.html">Administrator</a><ul> <li class="toctree-l1"><a class="reference internal" href="administrator.html">Administrator</a><ul>
<li class="toctree-l2"><a class="reference internal" href="administrator.html#fittrackee-fails-to-start"><cite>FitTrackee fails to start</cite></a></li> <li class="toctree-l2"><a class="reference internal" href="administrator.html#fittrackee-fails-to-start"><cite>FitTrackee fails to start</cite></a></li>
<li class="toctree-l2"><a class="reference internal" href="administrator.html#map-images-are-not-displayed-but-map-is-shown-in-workout-detail"><cite>Map images are not displayed but map is shown in Workout detail</cite></a></li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="user.html">User</a></li> <li class="toctree-l1"><a class="reference internal" href="user.html">User</a></li>
@ -152,7 +154,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
<title>User &#8212; FitTrackee 0.5.7 <title>User &#8212; FitTrackee 0.6.10
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -13,6 +13,7 @@
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> <script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script> <script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script> <script src="../_static/doctools.js"></script>
<link rel="index" title="Index" href="../genindex.html" /> <link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" /> <link rel="search" title="Search" href="../search.html" />
@ -40,7 +41,7 @@
</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.5.7 <span class="navbar-text navbar-version pull-left"><b>0.6.10
</b></span> </b></span>
</div> </div>
@ -61,6 +62,7 @@
aria-labelledby="dLabelGlobalToc"><ul class="current"> aria-labelledby="dLabelGlobalToc"><ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li> <li class="toctree-l1"><a class="reference internal" href="../features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li> <li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../cli.html">Command line interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/index.html">API documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="../api/index.html">API documentation</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Troubleshooting</a></li> <li class="toctree-l1 current"><a class="reference internal" href="index.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li> <li class="toctree-l1"><a class="reference internal" href="../changelog.html">Change log</a></li>
@ -126,7 +128,7 @@
<div class="body col-md-12 content" role="main"> <div class="body col-md-12 content" role="main">
<section id="user"> <section id="user">
<h1>User<a class="headerlink" href="#user" title="Permalink to this headline"></a></h1> <h1>User<a class="headerlink" href="#user" title="Permalink to this heading"></a></h1>
<p><code class="docutils literal notranslate"><span class="pre">TODO</span></code></p> <p><code class="docutils literal notranslate"><span class="pre">TODO</span></code></p>
</section> </section>
@ -143,7 +145,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 5.0.2.<br/>
</p> </p>
</div> </div>
</footer> </footer>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 KiB

After

Width:  |  Height:  |  Size: 369 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -4,8 +4,9 @@ Authentication
.. autoflask:: fittrackee:create_app() .. autoflask:: fittrackee:create_app()
:endpoints: :endpoints:
auth.register_user, auth.register_user,
auth.confirm_account,
auth.resend_account_confirmation_email,
auth.login_user, auth.login_user,
auth.logout_user,
auth.get_authenticated_user_profile, auth.get_authenticated_user_profile,
auth.edit_user, auth.edit_user,
auth.edit_user_preferences, auth.edit_user_preferences,
@ -14,4 +15,6 @@ Authentication
auth.edit_picture, auth.edit_picture,
auth.del_picture, auth.del_picture,
auth.request_password_reset, auth.request_password_reset,
auth.update_password auth.update_user_account,
auth.update_password,
auth.update_email

67
docsrc/source/cli.rst Normal file
View File

@ -0,0 +1,67 @@
Command line interface
######################
A command line interface (CLI) is available to manage database and users.
.. code-block:: bash
$ ftcli
Usage: ftcli [OPTIONS] COMMAND [ARGS]...
FitTrackee Command Line Interface
Options:
--help Show this message and exit.
Commands:
db Manage database.
users Manage users.
.. warning::
| The following commands are now deprecated and will be removed in a next version:
| - ``fittrackee_set_admin``
| - ``fittrackee_upgrade_db``
Database
~~~~~~~~
``ftcli db upgrade``
""""""""""""""""""""
.. versionadded:: 0.6.5
Apply migrations.
``ftcli db drop``
"""""""""""""""""
.. versionadded:: 0.6.5
Empty database and delete uploaded files, only on development environments.
Users
~~~~~
``ftcli users update``
""""""""""""""""""""""
.. versionadded:: 0.6.5
Modify a user account (admin rights, active status, email and password).
.. cssclass:: table-bordered
.. list-table::
:widths: 25 50
:header-rows: 1
* - Options
- Description
* - ``--set-admin BOOLEAN``
- Add/remove admin rights (when adding admin rights, it also activates user account if not active).
* - ``--activate``
- Activate user account.
* - ``--reset-password``
- Reset user password (a new password will be displayed).
* - ``--update-email EMAIL``
- Update user email.

View File

@ -44,9 +44,13 @@ Workouts
- average speed (**new in 0.5.1**) - average speed (**new in 0.5.1**)
- User records by sports: - User records by sports:
- average speed - average speed
- farest distance - farthest distance
- longest duration - longest duration
- maximum speed - maximum speed
.. note::
Records may differ from records displayed by the application that originally generated the gpx files.
- Workouts list and filter. Only sports with workouts are displayed in sport dropdown. - Workouts list and filter. Only sports with workouts are displayed in sport dropdown.
.. note:: .. note::
@ -55,9 +59,17 @@ Workouts
Account & preferences Account & preferences
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
- A user can create, update and deleted his account - A user can create, update and deleted his account.
- On registration, the user account is created with selected language in dropdown as user preference (*new in 0.6.9*).
- After registration, the user account is inactive and an email with confirmation instructions is sent to activate it.
A user with an inactive account cannot log in. (*new in 0.6.0*)
.. note::
In case email sending is not configured, a `command line <cli.html#ftcli-users-update>`__ allows to activate users account.
- A user can set language, timezone and first day of week. - A user can set language, timezone and first day of week.
- A user can reset his password (*new in 0.3.0*) - A user can reset his password (*new in 0.3.0*)
- A user can change his email address (*new in 0.6.0*)
- A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*) - A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*)
- A user can set sport preferences (*new in 0.5.0*): - A user can set sport preferences (*new in 0.5.0*):
- change sport color (used for sport image and charts) - change sport color (used for sport image and charts)
@ -82,15 +94,23 @@ Administration
- maximum size of uploaded files - maximum size of uploaded files
- maximum size of zip archive - maximum size of zip archive
- maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors. - maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.
- administrator email for contact (*new in 0.6.0*)
.. warning:: .. warning::
Updating server configuration may be necessary to handle large files (like `nginx <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_ for instance). Updating server configuration may be necessary to handle large files (like `nginx <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_ for instance).
.. note::
If email sending is disabled, a warning is displayed.
- **Users** - **Users**
- display users list and details - display and filter users list
- edit a user to add/remove administration rights - edit a user to:
- add/remove administration rights
- activate his account (*new in 0.6.0*)
- update his email (in case his account is locked) (*new in 0.6.0*)
- reset his password (in case his account is locked) (*new in 0.6.0*). If email sending is disabled, it is only possible via CLI.
- delete a user - delete a user
- **Sports** - **Sports**
@ -100,7 +120,9 @@ Administration
Translations Translations
^^^^^^^^^^^^ ^^^^^^^^^^^^
FitTrackee is available in English and French (which can be saved in the user preferences). FitTrackee is available in the following languages (which can be saved in the user preferences):
.. figure:: https://hosted.weblate.org/widgets/fittrackee/-/multi-auto.svg
Screenshots Screenshots

View File

@ -34,6 +34,7 @@ Table of contents
features features
installation installation
cli
api/index api/index
troubleshooting/index troubleshooting/index
changelog changelog

View File

@ -14,17 +14,17 @@ This application is written in Python (API) and Typescript (client):
- `Leaflet <https://leafletjs.com/>`__ to display map - `Leaflet <https://leafletjs.com/>`__ to display map
- `Chart.js <https://www.chartjs.org/>`__ to display charts with elevation and speed - `Chart.js <https://www.chartjs.org/>`__ to display charts with elevation and speed
Logo, sports and weather icons are made by `Freepik <https://www.freepik.com/>`__ from `www.flaticon.com <https://www.flaticon.com/>`__. | Logo, some sports and weather icons are made by `Freepik <https://www.freepik.com/>`__ from `www.flaticon.com <https://www.flaticon.com/>`__.
| FitTrackee also uses icons from `Fork Awesome <https://forkaweso.me>`__.
Prerequisites Prerequisites
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
- PostgreSQL database (10+)
- Redis for task queue
- Python 3.7+ - Python 3.7+
- PostgreSQL database (10+)
- SMTP provider and Redis for task queue (if email sending is enabled)
- API key from `Dark Sky <https://darksky.net/dev>`__ (not mandatory)
- `Poetry <https://poetry.eustace.io>`__ (for installation from sources only) - `Poetry <https://poetry.eustace.io>`__ (for installation from sources only)
- API key from `Dark Sky <https://darksky.net/dev>`__ [not mandatory]
- SMTP provider
- `Yarn <https://yarnpkg.com>`__ (for development only) - `Yarn <https://yarnpkg.com>`__ (for development only)
- Docker and Docker Compose (for development or evaluation purposes) - Docker and Docker Compose (for development or evaluation purposes)
@ -95,9 +95,9 @@ deployment method.
.. versionadded:: 0.4.0 .. versionadded:: 0.4.0
Directory containing uploaded files. **Absolute path** to the directory where `uploads` folder will be created.
:default: `fittrackee/uploads/` :default: `<application_directory>/fittrackee`
.. danger:: .. danger::
| With installation from PyPI, the directory will be located in | With installation from PyPI, the directory will be located in
@ -108,7 +108,7 @@ deployment method.
| Database URL with username and password, must be initialized in production environment. | Database URL with username and password, must be initialized in production environment.
| For example in dev environment : ``postgresql://fittrackee:fittrackee@localhost:5432/fittrackee`` | For example in dev environment : ``postgresql://fittrackee:fittrackee@localhost:5432/fittrackee``
.. danger:: .. warning::
| Since `SQLAlchemy update (1.4+) <https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b>`__, | Since `SQLAlchemy update (1.4+) <https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b>`__,
engine URL should begin with `postgresql://`. engine URL should begin with `postgresql://`.
@ -132,6 +132,13 @@ deployment method.
Email URL with credentials, see `Emails <installation.html#emails>`__. Email URL with credentials, see `Emails <installation.html#emails>`__.
.. versionchanged:: 0.6.5
:default: empty string
.. danger::
If the email URL is empty, email sending will be disabled.
.. warning:: .. warning::
If the email URL is invalid, the application may not start. If the email URL is invalid, the application may not start.
@ -168,6 +175,16 @@ deployment method.
:default: `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png` :default: `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png`
.. envvar:: STATICMAP_SUBDOMAINS 🆕
.. versionadded:: 0.6.10
| Some tile servers require a subdomain, see `Map tile server <installation.html#map-tile-server>`__.
| For instance: "a,b,c" for OSM France.
:default: empty string
.. envvar:: MAP_ATTRIBUTION .. envvar:: MAP_ATTRIBUTION
.. versionadded:: 0.4.0 .. versionadded:: 0.4.0
@ -177,11 +194,17 @@ deployment method.
:default: `&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors` :default: `&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`
.. envvar:: DEFAULT_STATICMAP 🆕 .. envvar:: DEFAULT_STATICMAP
.. versionadded:: 0.4.9 .. versionadded:: 0.4.9
If `True`, it keeps using default tile server to generate static maps. | If `True`, it keeps using default tile server to generate static maps (Komoot.de tile server).
| Otherwise, it uses the tile server set in `TILE_SERVER_URL <installation.html#envvar-TILE_SERVER_URL>`__.
.. versionchanged:: 0.6.10
| This variable is now case-insensitive.
| If `False`, depending on tile server, `subdomains <installation.html#envvar-STATICMAP_SUBDOMAINS>`__ may be mandatory.
:default: False :default: False
@ -209,12 +232,31 @@ To send emails, a valid ``EMAIL_URL`` must be provided:
- with SSL: ``smtp://username:password@smtp.example.com:465/?ssl=True`` - with SSL: ``smtp://username:password@smtp.example.com:465/?ssl=True``
- with STARTTLS: ``smtp://username:password@smtp.example.com:587/?tls=True`` - with STARTTLS: ``smtp://username:password@smtp.example.com:587/?tls=True``
.. warning::
| - If the email URL is invalid, the application may not start.
| - Sending emails with Office365 may not work if SMTP auth is disabled.
.. versionadded:: 0.5.3 .. versionchanged:: 0.5.3
| Credentials can be omitted: ``smtp://smtp.example.com:25``. | Credentials can be omitted: ``smtp://smtp.example.com:25``.
| If ``:<port>`` is omitted, the port defaults to 25. | If ``:<port>`` is omitted, the port defaults to 25.
.. warning::
| Since 0.6.0, newly created accounts must be confirmed (an email with confirmation instructions is sent after registration).
Emails sent by FitTrackee are:
- account confirmation instructions
- password reset request
- email change (to old and new email adresses)
- password change
.. versionchanged:: 0.6.5
| For single-user instance, it is possible to disable email sending with an empty ``EMAIL_URL`` (in this case, no need to start dramatiq workers).
| A `CLI <cli.html#ftcli-users-update>`__ is available to activate account and modify email and password.
Map tile server Map tile server
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
.. versionadded:: 0.4.0 .. versionadded:: 0.4.0
@ -230,6 +272,20 @@ To keep using **ThunderForest Outdoors**, the configuration is:
.. note:: .. note::
| Check the terms of service of tile provider for map attribution | Check the terms of service of tile provider for map attribution
.. versionchanged:: 0.6.10
Since the tile server can be used for static map generation, some servers require a subdomain.
For instance, to set OSM France tile server, the expected values are:
- ``TILE_SERVER_URL=https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png``
- ``MAP_ATTRIBUTION='fond de carte par <a href="http://www.openstreetmap.fr/mentions-legales/" target="_blank" rel="nofollow noopener">OpenStreetMap France</a>, sous&nbsp;<a href="http://creativecommons.org/licenses/by-sa/2.0/fr/" target="_blank" rel="nofollow noopener">licence CC BY-SA</a>'``
- ``STATICMAP_SUBDOMAINS=a,b,c``
The subdomain will be chosen randomly.
Installation Installation
~~~~~~~~~~~~ ~~~~~~~~~~~~
@ -273,7 +329,7 @@ For instance, copy and update ``.env`` file from ``.env.example`` and source the
.. code-block:: bash .. code-block:: bash
$ fittrackee_upgrade_db $ ftcli db upgrade
- Start the application - Start the application
@ -281,7 +337,7 @@ For instance, copy and update ``.env`` file from ``.env.example`` and source the
$ fittrackee $ fittrackee
- Start task queue workers - Start task queue workers if email sending is enabled.
.. code-block:: bash .. code-block:: bash
@ -292,12 +348,14 @@ For instance, copy and update ``.env`` file from ``.env.example`` and source the
- Open http://localhost:3000 and register - Open http://localhost:3000 and register
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ fittrackee_set_admin <username> $ ftcli users update <username> --set-admin true
.. note::
If the user account is inactive, it activates it.
From sources From sources
^^^^^^^^^^^^ ^^^^^^^^^^^^
@ -352,12 +410,14 @@ Dev environment
- Open http://localhost:3000 and register - Open http://localhost:3000 and register
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ make set-admin USERNAME=<username> $ make user-set-admin USERNAME=<username>
.. note::
If the user account is inactive, it activates it.
Production environment Production environment
"""""""""""""""""""""" """"""""""""""""""""""
@ -365,13 +425,13 @@ Production environment
.. warning:: .. warning::
| Note that FitTrackee is under heavy development, some features may be unstable. | Note that FitTrackee is under heavy development, some features may be unstable.
- Download the last release (for now, it is the release v0.5.7): - Download the last release (for now, it is the release v0.6.10):
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.5.7.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.10.tar.gz
$ tar -xzf v0.5.7.tar.gz $ tar -xzf v0.6.10.tar.gz
$ mv FitTrackee-0.5.7 FitTrackee $ mv FitTrackee-0.6.10 FitTrackee
$ cd FitTrackee $ cd FitTrackee
- Create **.env** from example and update it - Create **.env** from example and update it
@ -396,14 +456,19 @@ Production environment
$ make run $ make run
.. note::
If email sending is disabled: ``$ make run-server``
- Open http://localhost:5000 and register - Open http://localhost:5000 and register
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ make set-admin USERNAME=<username> $ make user-set-admin USERNAME=<username>
.. note::
If the user account is inactive, it activates it.
Upgrade Upgrade
~~~~~~~ ~~~~~~~
@ -417,7 +482,7 @@ Upgrade
From PyPI From PyPI
^^^^^^^^^ ^^^^^^^^^
- Activate the virtualenv - Stop the application and activate the virtualenv
- Upgrade with pip - Upgrade with pip
@ -436,10 +501,9 @@ From PyPI
.. code-block:: bash .. code-block:: bash
$ fittrackee_upgrade_db $ ftcli db upgrade
- Restart the application and task queue workers (if email sending is enabled).
- Restart the application and task queue workers.
From sources From sources
@ -487,13 +551,13 @@ Prod environment
- Change to the directory where FitTrackee directory is located - Change to the directory where FitTrackee directory is located
- Download the last release (for now, it is the release v0.5.7) and overwrite existing files: - Download the last release (for now, it is the release v0.6.10) and overwrite existing files:
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.5.7.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.10.tar.gz
$ tar -xzf v0.5.7.tar.gz $ tar -xzf v0.6.10.tar.gz
$ cp -R FitTrackee-0.5.7/* FitTrackee/ $ cp -R FitTrackee-0.6.10/* FitTrackee/
$ cd FitTrackee $ cd FitTrackee
- Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__). - Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__).
@ -516,6 +580,8 @@ Prod environment
$ make run $ make run
.. note::
If email sending is disabled: ``$ make run-server``
Deployment Deployment
~~~~~~~~~~ ~~~~~~~~~~
@ -554,6 +620,7 @@ Examples (to update depending on your application configuration and given distri
Environment="SENDER_EMAIL=" Environment="SENDER_EMAIL="
Environment="REDIS_URL=" Environment="REDIS_URL="
Environment="TILE_SERVER_URL=" Environment="TILE_SERVER_URL="
Environment="STATICMAP_SUBDOMAINS="
Environment="MAP_ATTRIBUTION=" Environment="MAP_ATTRIBUTION="
Environment="WEATHER_API_KEY=" Environment="WEATHER_API_KEY="
WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY> WorkingDirectory=/home/<USER>/<FITTRACKEE DIRECTORY>
@ -641,8 +708,7 @@ Installation
.. versionadded:: 0.4.4 .. versionadded:: 0.4.4
For evaluation purposes , docker files are available, For evaluation purposes, docker files are available, installing **FitTrackee** from **sources**.
installing **FitTrackee** from **sources**.
- To install **FitTrackee** with database initialisation and run the application and dramatiq workers: - To install **FitTrackee** with database initialisation and run the application and dramatiq workers:
@ -650,18 +716,22 @@ installing **FitTrackee** from **sources**.
$ git clone https://github.com/SamR1/FitTrackee.git $ git clone https://github.com/SamR1/FitTrackee.git
$ cd FitTrackee $ cd FitTrackee
$ cp .env.docker .env
$ make docker-build docker-run docker-init $ make docker-build docker-run docker-init
Open http://localhost:5000 and register. Open http://localhost:5000 and register.
Open http://localhost:8025 to access `MailHog interface <https://github.com/mailhog/MailHog>`_ (email testing tool) Open http://localhost:8025 to access `MailHog interface <https://github.com/mailhog/MailHog>`_ (email testing tool)
- To set admin rights to the newly created account, use the following command: - To set admin rights to the newly created account, use the following command line:
.. code:: bash .. code:: bash
$ make docker-set-admin USERNAME=<username> $ make docker-set-admin USERNAME=<username>
.. note::
If the user account is inactive, it activates it.
- To stop **Fittrackee**: - To stop **Fittrackee**:
.. code-block:: bash .. code-block:: bash

View File

@ -5,10 +5,24 @@ Administrator
`FitTrackee fails to start` `FitTrackee fails to start`
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Check the database URL in `Environment variables <../installation.html#envvar-DATABASE_URL>`__ if the following error is displayed in **gunicorn** logs: - Check the database URL in `environment variables <../installation.html#envvar-DATABASE_URL>`__ if the following error is displayed in **gunicorn** logs:
.. code:: .. code::
sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres
It must start with `postgresql://` (engine URLs starting with `postgres://` are no longer supported). It must start with `postgresql://` (engine URLs starting with `postgres://` are no longer supported).
- Check the email URL in `environment variables <../installation.html#envvar-EMAIL_URL>`__ if the following error is displayed in **gunicorn** logs:
.. code::
fittrackee.emails.exceptions.InvalidEmailUrlScheme
A valid ``EMAIL_URL`` must be provided (see `emails <../installation.html#emails>`__).
`Map images are not displayed but map is shown in Workout detail`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Check the path in `environment variables <../installation.html#envvar-UPLOAD_FOLDER>`__. ``UPLOAD_FOLDER`` must be set with an absolute path.

View File

@ -3,7 +3,6 @@ Troubleshooting
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: Endpoints:
administrator administrator
user user

View File

@ -1,3 +1,5 @@
from selenium.webdriver.common.by import By
from .utils import TEST_URL from .utils import TEST_URL
@ -9,7 +11,7 @@ class TestIndex:
def test_navbar_contains_all_links(self, selenium): def test_navbar_contains_all_links(self, selenium):
selenium.get(TEST_URL) selenium.get(TEST_URL)
nav = selenium.find_element_by_id('nav').text nav = selenium.find_element(By.ID, 'nav').text
assert "FitTrackee" in nav assert "FitTrackee" in nav
assert "Login" in nav assert "Login" in nav
assert "Register" in nav assert "Register" in nav

View File

@ -1,9 +1,6 @@
from .utils import ( from selenium.webdriver.common.by import By
TEST_URL,
assert_navbar, from .utils import TEST_URL, login_valid_user, register_valid_user_and_logout
login_valid_user,
register_valid_user_and_logout,
)
URL = f'{TEST_URL}/login' URL = f'{TEST_URL}/login'
@ -12,32 +9,42 @@ class TestLogin:
def test_navbar_contains_login(self, selenium): def test_navbar_contains_login(self, selenium):
selenium.get(URL) selenium.get(URL)
nav = selenium.find_element_by_id('nav').text nav = selenium.find_element(By.ID, 'nav').text
assert 'Login' in nav assert 'Login' in nav
def test_it_displays_login_form(self, selenium): def test_it_displays_login_form(self, selenium):
selenium.get(URL) selenium.get(URL)
inputs = selenium.find_elements_by_tag_name('input') inputs = selenium.find_elements(By.TAG_NAME, 'input')
assert len(inputs) == 2 assert len(inputs) == 2
assert inputs[0].get_attribute('id') == 'email' assert inputs[0].get_attribute('id') == 'email'
assert inputs[0].get_attribute('type') == 'email' assert inputs[0].get_attribute('type') == 'email'
assert inputs[1].get_attribute('id') == 'password' assert inputs[1].get_attribute('id') == 'password'
assert inputs[1].get_attribute('type') == 'password' assert inputs[1].get_attribute('type') == 'password'
button = selenium.find_element_by_tag_name('button') button = selenium.find_element(By.TAG_NAME, 'button')
assert button.get_attribute('type') == 'submit' assert button.get_attribute('type') == 'submit'
assert 'Log in' in button.text assert 'Log in' in button.text
links = selenium.find_elements_by_class_name('links') links = selenium.find_elements(By.CLASS_NAME, 'links')
assert links[0].tag_name == 'a' assert links[0].tag_name == 'a'
assert 'Register' in links[0].text assert 'Register' in links[0].text
assert links[1].tag_name == 'a' assert links[1].tag_name == 'a'
assert 'Forgot password?' in links[1].text assert 'Forgot password?' in links[1].text
assert links[2].tag_name == 'a'
assert "Didn't received instructions?" in links[2].text
def test_user_can_log_in(self, selenium): def test_user_can_log_in(self, selenium):
user = register_valid_user_and_logout(selenium) user = register_valid_user_and_logout(selenium)
login_valid_user(selenium, user) login_valid_user(selenium, user)
assert_navbar(selenium, user) nav = selenium.find_element(By.ID, '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 a workout' in nav
assert user['username'] in nav
assert 'Logout' in nav

View File

@ -1,16 +1,18 @@
from selenium.webdriver.common.by import By
from .utils import register_valid_user from .utils import register_valid_user
class TestLogout: class TestLogout:
def test_user_can_log_out(self, selenium): def test_user_can_log_out(self, selenium):
user = register_valid_user(selenium) user = register_valid_user(selenium)
user_menu = selenium.find_element_by_class_name('nav-items-user-menu') user_menu = selenium.find_element(By.CLASS_NAME, 'nav-items-user-menu')
logout_link = user_menu.find_elements_by_class_name('nav-item')[2] logout_link = user_menu.find_elements(By.CLASS_NAME, 'nav-item')[2]
logout_link.click() logout_link.click()
selenium.implicitly_wait(1) selenium.implicitly_wait(1)
nav = selenium.find_element_by_id('nav').text nav = selenium.find_element(By.ID, 'nav').text
assert 'Register' in nav assert 'Register' in nav
assert 'Login' in nav assert 'Login' in nav
assert user['username'] not in nav assert user['username'] not in nav

View File

@ -1,20 +1,24 @@
from .utils import TEST_URL, register_valid_user from selenium.webdriver.common.by import By
URL = f'{TEST_URL}/profile' from .utils import register_valid_user
class TestProfile: class TestProfile:
def test_it_displays_user_profile(self, selenium): def test_it_displays_user_profile(self, selenium):
user = register_valid_user(selenium) user = register_valid_user(selenium)
selenium.get(URL) app_menu = selenium.find_element(By.CLASS_NAME, 'nav-items-user-menu')
user_header = selenium.find_element_by_class_name('user-header') profile_link = app_menu.find_elements(By.CLASS_NAME, 'nav-item')[1]
profile_link.click()
selenium.implicitly_wait(1)
user_header = selenium.find_element(By.CLASS_NAME, 'user-header')
assert user['username'] in user_header.text assert user['username'] in user_header.text
assert '0\nworkouts' in user_header.text assert '0\nworkouts' in user_header.text
assert '0\nkm' in user_header.text assert '0\nkm' in user_header.text
assert '0\nsports' in user_header.text assert '0\nsports' in user_header.text
user_infos = selenium.find_element_by_id('user-infos') user_infos = selenium.find_element(By.ID, 'user-infos')
assert 'Registration date' in user_infos.text assert 'Registration date' in user_infos.text
assert 'First name' in user_infos.text assert 'First name' in user_infos.text
assert 'Last name' in user_infos.text assert 'Last name' in user_infos.text

View File

@ -1,9 +1,9 @@
from selenium.webdriver.common.by import By
from .utils import ( from .utils import (
TEST_URL, TEST_URL,
assert_navbar,
random_string, random_string,
register, register,
register_valid_user,
register_valid_user_and_logout, register_valid_user_and_logout,
) )
@ -15,7 +15,7 @@ class TestRegistration:
selenium.get(URL) selenium.get(URL)
selenium.implicitly_wait(1) selenium.implicitly_wait(1)
inputs = selenium.find_elements_by_tag_name('input') inputs = selenium.find_elements(By.TAG_NAME, 'input')
assert len(inputs) == 4 assert len(inputs) == 4
assert inputs[0].get_attribute('id') == 'username' assert inputs[0].get_attribute('id') == 'username'
assert inputs[0].get_attribute('type') == 'text' assert inputs[0].get_attribute('type') == 'text'
@ -23,21 +23,40 @@ class TestRegistration:
assert inputs[1].get_attribute('type') == 'email' assert inputs[1].get_attribute('type') == 'email'
assert inputs[2].get_attribute('id') == 'password' assert inputs[2].get_attribute('id') == 'password'
assert inputs[2].get_attribute('type') == 'password' assert inputs[2].get_attribute('type') == 'password'
assert inputs[3].get_attribute('id') == 'confirm-password'
assert inputs[3].get_attribute('type') == 'password'
button = selenium.find_element_by_tag_name('button') form_infos = selenium.find_elements(By.CLASS_NAME, 'form-info')
assert len(form_infos) == 3
assert form_infos[0].text == (
'3 to 30 characters required, only alphanumeric characters and '
'the underscore character "_" allowed.'
)
assert form_infos[1].text == 'Enter a valid email address.'
assert form_infos[2].text == 'At least 8 characters required.'
button = selenium.find_element(By.TAG_NAME, 'button')
assert button.get_attribute('type') == 'submit' assert button.get_attribute('type') == 'submit'
assert 'Register' in button.text assert 'Register' in button.text
link = selenium.find_element_by_class_name('links') links = selenium.find_elements(By.CLASS_NAME, 'links')
assert link.tag_name == 'a' assert links[0].tag_name == 'a'
assert 'Login' in link.text assert 'Login' in links[0].text
assert links[1].tag_name == 'a'
assert "Didn't received instructions?" in links[1].text
def test_user_can_register(self, selenium): def test_user_can_register(self, selenium):
user = register_valid_user(selenium) user = {
'username': random_string(),
'email': f'{random_string()}@example.com',
'password': 'p@ssw0rd',
}
assert_navbar(selenium, user) register(selenium, user)
message = selenium.find_element(By.CLASS_NAME, 'success-message').text
assert (
'A link to activate your account has been '
'emailed to the address provided.'
) in message
def test_user_can_not_register_with_invalid_email(self, selenium): def test_user_can_not_register_with_invalid_email(self, selenium):
user_name = random_string() user_name = random_string()
@ -45,13 +64,12 @@ class TestRegistration:
'username': user_name, 'username': user_name,
'email': user_name, 'email': user_name,
'password': 'p@ssw0rd', 'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
} }
register(selenium, user_infos) register(selenium, user_infos)
assert selenium.current_url == URL assert selenium.current_url == URL
nav = selenium.find_element_by_id('nav').text nav = selenium.find_element(By.ID, 'nav').text
assert 'Register' in nav assert 'Register' in nav
assert 'Login' in nav assert 'Login' in nav
@ -64,30 +82,20 @@ class TestRegistration:
register(selenium, user) register(selenium, user)
assert selenium.current_url == URL assert selenium.current_url == URL
errors = selenium.find_element_by_class_name('error-message').text errors = selenium.find_element(By.CLASS_NAME, 'error-message').text
assert 'Sorry, that user already exists.' in errors assert 'Sorry, that username is already taken.' in errors
def test_user_can_not_register_if_email_is_already_taken(self, selenium): def test_user_does_not_return_error_if_email_is_already_taken(
self, selenium
):
user = register_valid_user_and_logout(selenium) user = register_valid_user_and_logout(selenium)
user['username'] = random_string() user['username'] = random_string()
register(selenium, user) register(selenium, user)
assert selenium.current_url == URL assert selenium.current_url == f'{TEST_URL}/login'
errors = selenium.find_element_by_class_name('error-message').text message = selenium.find_element(By.CLASS_NAME, 'success-message').text
assert 'Sorry, that user already exists.' in errors assert (
'A link to activate your account has been '
def test_it_displays_error_if_passwords_do_not_match(self, selenium): 'emailed to the address provided.'
user_name = random_string() ) in message
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_class_name('error-message').text
assert 'password and password confirmation don\'t match' in errors

View File

@ -1,3 +1,4 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select, WebDriverWait from selenium.webdriver.support.ui import Select, WebDriverWait
@ -7,36 +8,36 @@ from .utils import TEST_URL, register_valid_user
class TestWorkout: class TestWorkout:
def test_user_can_add_workout_without_gpx(self, selenium): def test_user_can_add_workout_without_gpx(self, selenium):
register_valid_user(selenium) register_valid_user(selenium)
app_menu = selenium.find_element_by_class_name('nav-items-app-menu') app_menu = selenium.find_element(By.CLASS_NAME, 'nav-items-app-menu')
add_workout_link = app_menu.find_elements_by_class_name('nav-item')[3] add_workout_link = app_menu.find_elements(By.CLASS_NAME, 'nav-item')[3]
add_workout_link.click() add_workout_link.click()
selenium.implicitly_wait(1) selenium.implicitly_wait(1)
radio_button = selenium.find_element_by_id('withoutGpx') radio_button = selenium.find_element(By.ID, 'withoutGpx')
radio_button.click() radio_button.click()
select = Select(selenium.find_element_by_id('sport')) select = Select(selenium.find_element(By.ID, 'sport'))
select.select_by_index(1) select.select_by_index(1)
selenium.find_element_by_name('title').send_keys('Workout title') selenium.find_element(By.NAME, 'title').send_keys('Workout title')
selenium.find_element_by_name('workout-date').send_keys('2018-12-20') selenium.find_element(By.NAME, 'workout-date').send_keys('2018-12-20')
selenium.find_element_by_name('workout-time').send_keys('14:05') selenium.find_element(By.NAME, 'workout-time').send_keys('14:05')
selenium.find_element_by_name('workout-duration-hour').send_keys('01') selenium.find_element(By.NAME, 'workout-duration-hour').send_keys('01')
selenium.find_element_by_name('workout-duration-minutes').send_keys( selenium.find_element(By.NAME, 'workout-duration-minutes').send_keys(
'00' '00'
) )
selenium.find_element_by_name('workout-duration-seconds').send_keys( selenium.find_element(By.NAME, 'workout-duration-seconds').send_keys(
'00' '00'
) )
selenium.find_element_by_name('workout-distance').send_keys('10') selenium.find_element(By.NAME, 'workout-distance').send_keys('10')
confirm_button = selenium.find_element_by_class_name('confirm') confirm_button = selenium.find_element(By.CLASS_NAME, 'confirm')
confirm_button.click() confirm_button.click()
WebDriverWait(selenium, 10).until( WebDriverWait(selenium, 10).until(
EC.url_changes(f"{TEST_URL}/workouts/add") EC.url_changes(f"{TEST_URL}/workouts/add")
) )
workout_details = selenium.find_element_by_id('workout-info').text workout_details = selenium.find_element(By.ID, 'workout-info').text
assert 'Duration: 1:00:00' in workout_details assert 'Duration: 1:00:00' in workout_details
assert 'Distance: 10 km' in workout_details assert 'Distance: 10 km' in workout_details
assert 'Average Speed: 10 km/h' in workout_details assert 'Average Speed: 10 km/h' in workout_details

View File

@ -1,43 +1,49 @@
import os import os
import random import random
import re
import string import string
import time
import requests
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
from urllib3.util import parse_url
TEST_APP_URL = os.getenv('TEST_APP_URL') TEST_APP_URL = os.getenv('TEST_APP_URL')
TEST_CLIENT_URL = os.getenv('TEST_CLIENT_URL') TEST_CLIENT_URL = os.getenv('TEST_CLIENT_URL')
E2E_ARGS = os.getenv('E2E_ARGS') E2E_ARGS = os.getenv('E2E_ARGS')
TEST_URL = TEST_CLIENT_URL if E2E_ARGS == 'client' else TEST_APP_URL TEST_URL = TEST_CLIENT_URL if E2E_ARGS == 'client' else TEST_APP_URL
EMAIL_URL = os.getenv('EMAIL_URL', 'smtp://none:none@0.0.0.0:1025')
parsed_email_url = parse_url(EMAIL_URL)
EMAIL_API_URL = f'http://{parsed_email_url.host}:8025'
def random_string(length=8): def random_string(length=8):
return ''.join(random.choice(string.ascii_letters) for x in range(length)) return ''.join(random.choice(string.ascii_letters) for _ in range(length))
def register(selenium, user): def register(selenium, user):
selenium.get(f'{TEST_URL}/register') selenium.get(f'{TEST_URL}/register')
selenium.implicitly_wait(1) selenium.implicitly_wait(1)
username = selenium.find_element_by_id('username') username = selenium.find_element(By.ID, 'username')
username.send_keys(user.get('username')) username.send_keys(user.get('username'))
email = selenium.find_element_by_id('email') email = selenium.find_element(By.ID, 'email')
email.send_keys(user.get('email')) email.send_keys(user.get('email'))
password = selenium.find_element_by_id('password') password = selenium.find_element(By.ID, 'password')
password.send_keys(user.get('password')) password.send_keys(user.get('password'))
password_conf = selenium.find_element_by_id('confirm-password') submit_button = selenium.find_element(By.TAG_NAME, 'button')
password_conf.send_keys(user.get('password_conf'))
submit_button = selenium.find_element_by_tag_name('button')
submit_button.click() submit_button.click()
def login(selenium, user): def login(selenium, user):
selenium.get(f'{TEST_URL}/login') selenium.get(f'{TEST_URL}/login')
selenium.implicitly_wait(1) selenium.implicitly_wait(1)
email = selenium.find_element_by_id('email') email = selenium.find_element(By.ID, 'email')
email.send_keys(user.get('email')) email.send_keys(user.get('email'))
password = selenium.find_element_by_id('password') password = selenium.find_element(By.ID, 'password')
password.send_keys(user.get('password')) password.send_keys(user.get('password'))
submit_button = selenium.find_element_by_tag_name('button') submit_button = selenium.find_element(By.TAG_NAME, 'button')
submit_button.click() submit_button.click()
@ -47,44 +53,36 @@ def register_valid_user(selenium):
'username': user_name, 'username': user_name,
'email': f'{user_name}@example.com', 'email': f'{user_name}@example.com',
'password': 'p@ssw0rd', 'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
} }
register(selenium, user) register(selenium, user)
WebDriverWait(selenium, 15).until(EC.url_changes(f"{TEST_URL}/register")) WebDriverWait(selenium, 30).until(EC.url_changes(f"{TEST_URL}/register"))
confirm_account(selenium, user)
return user return user
def register_valid_user_and_logout(selenium): def register_valid_user_and_logout(selenium):
user_name = random_string() user = register_valid_user(selenium)
user = { user_menu = selenium.find_element(By.CLASS_NAME, 'nav-items-user-menu')
'username': user_name, logout_link = user_menu.find_elements(By.CLASS_NAME, 'nav-item')[2]
'email': f'{user_name}@example.com',
'password': 'p@ssw0rd',
'password_conf': 'p@ssw0rd',
}
register(selenium, user)
WebDriverWait(selenium, 15).until(EC.url_changes(f"{TEST_URL}/register"))
user_menu = selenium.find_element_by_class_name('nav-items-user-menu')
logout_link = user_menu.find_elements_by_class_name('nav-item')[2]
logout_link.click() logout_link.click()
selenium.implicitly_wait(1)
return user return user
def confirm_account(selenium, user):
time.sleep(1)
response = requests.get(
f"{EMAIL_API_URL}/api/v2/search?kind=to&query={user['email']}"
)
response.raise_for_status()
results = response.json()
message = results['items'][0]['Content']['Body']
link = re.search(r'Verify your email: (.+?)\r\n', message).groups()[0]
link = link.replace('http://0.0.0.0:5000', TEST_URL)
selenium.get(link)
WebDriverWait(selenium, 15).until(EC.url_changes(link))
def login_valid_user(selenium, user): def login_valid_user(selenium, user):
login(selenium, user) login(selenium, user)
WebDriverWait(selenium, 10).until(EC.url_changes(f"{TEST_URL}/login")) WebDriverWait(selenium, 10).until(EC.url_changes(f"{TEST_URL}/login"))
return user return user
def assert_navbar(selenium, user):
nav = selenium.find_element_by_id('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 a workout' in nav
assert user['username'] in nav
assert 'Logout' in nav

View File

@ -1,6 +1,6 @@
import logging import logging
import os import os
import shutil import re
from importlib import import_module, reload from importlib import import_module, reload
from typing import Any from typing import Any
@ -15,10 +15,12 @@ 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
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.exc import ProgrammingError
from fittrackee.emails.email import EmailService from fittrackee.emails.email import EmailService
from fittrackee.request import CustomRequest
VERSION = __version__ = '0.5.7' VERSION = __version__ = '0.6.10'
db = SQLAlchemy() db = SQLAlchemy()
bcrypt = Bcrypt() bcrypt = Bcrypt()
migrate = Migrate() migrate = Migrate()
@ -33,9 +35,17 @@ logging.basicConfig(
appLog = logging.getLogger('fittrackee') appLog = logging.getLogger('fittrackee')
def create_app() -> Flask: class CustomFlask(Flask):
# add custom Request to handle user-agent parsing
# (removed in Werkzeug 2.1)
request_class = CustomRequest
def create_app(init_email: bool = True) -> Flask:
# instantiate the app # instantiate the app
app = Flask(__name__, static_folder='dist/static', template_folder='dist') app = CustomFlask(
__name__, static_folder='dist/static', template_folder='dist'
)
# set config # set config
with app.app_context(): with app.app_context():
@ -54,8 +64,15 @@ def create_app() -> Flask:
migrate.init_app(app, db) migrate.init_app(app, db)
dramatiq.init_app(app) dramatiq.init_app(app)
# set up email # set up email if 'EMAIL_URL' is initialized
email_service.init_email(app) if init_email:
if app.config['EMAIL_URL']:
email_service.init_email(app)
app.config['CAN_SEND_EMAILS'] = True
else:
appLog.warning(
'EMAIL_URL is not provided, email sending is deactivated.'
)
# get configuration from database # get configuration from database
from .application.utils import ( from .application.utils import (
@ -66,9 +83,16 @@ def create_app() -> Flask:
with app.app_context(): with app.app_context():
# Note: check if "app_config" table exist to avoid errors when # Note: check if "app_config" table exist to avoid errors when
# dropping tables on dev environments # dropping tables on dev environments
if db.engine.dialect.has_table(db.engine.connect(), 'app_config'): try:
db_app_config = get_or_init_config() if db.engine.dialect.has_table(db.engine.connect(), 'app_config'):
update_app_config_from_database(app, db_app_config) db_app_config = get_or_init_config()
update_app_config_from_database(app, db_app_config)
except ProgrammingError as e:
# avoid error on AppConfig migration
if re.match(
r'psycopg2.errors.UndefinedColumn(.*)app_config.', str(e)
):
pass
from .application.app_config import config_blueprint # noqa from .application.app_config import config_blueprint # noqa
from .users.auth import auth_blueprint # noqa from .users.auth import auth_blueprint # noqa
@ -96,7 +120,7 @@ def create_app() -> Flask:
appLog.setLevel(logging.DEBUG) appLog.setLevel(logging.DEBUG)
# Enable CORS # Enable CORS
@app.after_request @app.after_request # type: ignore
def after_request(response: Response) -> Response: def after_request(response: Response) -> Response:
response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add( response.headers.add(
@ -129,17 +153,4 @@ def create_app() -> Flask:
else: else:
return render_template('index.html') return render_template('index.html')
@app.cli.command('drop-db')
def drop_db() -> None:
"""Empty database and delete uploaded files for dev environments."""
if app_settings == 'fittrackee.config.ProductionConfig':
print('This is a production server, aborting!')
return
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.')
return app return app

View File

@ -3,16 +3,23 @@
import os import os
from typing import Dict, Optional from typing import Dict, Optional
import click
import gunicorn.app.base import gunicorn.app.base
from flask import Flask from flask import Flask
from flask_migrate import upgrade from flask_migrate import upgrade
from fittrackee import create_app from fittrackee import create_app
from fittrackee.users.exceptions import UserNotFoundException
from fittrackee.users.utils.admin import UserManagerService
HOST = os.getenv('HOST', '0.0.0.0') HOST = os.getenv('HOST', '127.0.0.1')
PORT = os.getenv('PORT', '5000') PORT = os.getenv('PORT', '5000')
WORKERS = os.getenv('APP_WORKERS', 1) WORKERS = os.getenv('APP_WORKERS', 1)
BASEDIR = os.path.abspath(os.path.dirname(__file__)) BASEDIR = os.path.abspath(os.path.dirname(__file__))
WARNING_MESSAGE = (
"\nThis command is deprecated, it will be removed in a next version.\n"
"Please use ftcli instead.\n"
)
app = create_app() app = create_app()
@ -37,7 +44,39 @@ class StandaloneApplication(gunicorn.app.base.BaseApplication):
return self.application return self.application
# DEPRECATED COMMANDS
@click.group()
def users_cli() -> None:
pass
@users_cli.command('set_admin')
@click.argument('username')
def set_admin(username: str) -> None:
"""
[deprecated] Set admin rights for given user.
It will be removed in a next version.
"""
print(WARNING_MESSAGE)
with app.app_context():
try:
user_manager_service = UserManagerService(username)
user_manager_service.update(
is_admin=True,
)
print(f"User '{username}' updated.")
except UserNotFoundException:
print(f"User '{username}' not found.")
def upgrade_db() -> None: def upgrade_db() -> None:
"""
[deprecated] Apply migrations.
It will be removed in a next version.
"""
print(WARNING_MESSAGE)
with app.app_context(): with app.app_context():
upgrade(directory=BASEDIR + '/migrations') upgrade(directory=BASEDIR + '/migrations')

View File

@ -11,6 +11,7 @@ from fittrackee.responses import (
) )
from fittrackee.users.decorators import authenticate_as_admin from fittrackee.users.decorators import authenticate_as_admin
from fittrackee.users.models import User from fittrackee.users.models import User
from fittrackee.users.utils.controls import is_valid_email
from .models import AppConfig from .models import AppConfig
from .utils import update_app_config_from_database, verify_app_config from .utils import update_app_config_from_database, verify_app_config
@ -39,13 +40,15 @@ def get_application_config() -> Union[Dict, HttpResponse]:
{ {
"data": { "data": {
"admin_contact": "admin@example.com",
"gpx_limit_import": 10, "gpx_limit_import": 10,
"is_email_sending_enabled": true,
"is_registration_enabled": false, "is_registration_enabled": false,
"max_single_file_size": 1048576, "max_single_file_size": 1048576,
"max_zip_file_size": 10485760,
"max_users": 0, "max_users": 0,
"max_zip_file_size": 10485760,
"map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors" "map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
"version": "0.5.7" "version": "0.6.10"
}, },
"status": "success" "status": "success"
} }
@ -87,20 +90,25 @@ def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
{ {
"data": { "data": {
"admin_contact": "admin@example.com",
"gpx_limit_import": 10, "gpx_limit_import": 10,
"is_registration_enabled": true, "is_email_sending_enabled": true,
"is_registration_enabled": false,
"max_single_file_size": 1048576, "max_single_file_size": 1048576,
"max_users": 10,
"max_zip_file_size": 10485760, "max_zip_file_size": 10485760,
"max_users": 10 "map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
"version": "0.6.10"
}, },
"status": "success" "status": "success"
} }
:<json string admin_contact: email to contact the administrator
:<json integer gpx_limit_import: max number of files in zip archive :<json integer gpx_limit_import: max number of files in zip archive
:<json boolean is_registration_enabled: is registration enabled ? :<json boolean is_registration_enabled: is registration enabled ?
:<json integer max_single_file_size: max size of a single file :<json integer max_single_file_size: max size of a single file
:<json integer max_zip_file_size: max size of a zip archive
:<json integer max_users: max users allowed to register on instance :<json integer max_users: max users allowed to register on instance
:<json integer max_zip_file_size: max size of a zip archive
:reqheader Authorization: OAuth 2.0 Bearer Token :reqheader Authorization: OAuth 2.0 Bearer Token
@ -110,6 +118,7 @@ def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
- provide a valid auth token - provide a valid auth token
- signature expired, please log in again - signature expired, please log in again
- invalid token, please log in again - invalid token, please log in again
- valid email must be provided for admin contact
:statuscode 403: you do not have permissions :statuscode 403: you do not have permissions
:statuscode 500: error when updating configuration :statuscode 500: error when updating configuration
""" """
@ -118,6 +127,9 @@ def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
return InvalidPayloadErrorResponse() return InvalidPayloadErrorResponse()
ret = verify_app_config(config_data) ret = verify_app_config(config_data)
admin_contact = config_data.get('admin_contact')
if admin_contact and not is_valid_email(admin_contact):
ret.append('valid email must be provided for admin contact')
if ret: if ret:
return InvalidPayloadErrorResponse(message=ret) return InvalidPayloadErrorResponse(message=ret)
@ -133,6 +145,8 @@ def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
config.max_zip_file_size = config_data.get('max_zip_file_size') config.max_zip_file_size = config_data.get('max_zip_file_size')
if 'max_users' in config_data: if 'max_users' in config_data:
config.max_users = config_data.get('max_users') config.max_users = config_data.get('max_users')
if 'admin_contact' in config_data:
config.admin_contact = admin_contact if admin_contact else None
if config.max_zip_file_size < config.max_single_file_size: if config.max_zip_file_size < config.max_single_file_size:
return InvalidPayloadErrorResponse( return InvalidPayloadErrorResponse(

View File

@ -23,6 +23,7 @@ class AppConfig(BaseModel):
db.Integer, default=1048576, nullable=False db.Integer, default=1048576, nullable=False
) )
max_zip_file_size = db.Column(db.Integer, default=10485760, nullable=False) max_zip_file_size = db.Column(db.Integer, default=10485760, nullable=False)
admin_contact = db.Column(db.String(255), nullable=True)
@property @property
def is_registration_enabled(self) -> bool: def is_registration_enabled(self) -> bool:
@ -43,7 +44,9 @@ class AppConfig(BaseModel):
def serialize(self) -> Dict: def serialize(self) -> Dict:
return { return {
'admin_contact': self.admin_contact,
'gpx_limit_import': self.gpx_limit_import, 'gpx_limit_import': self.gpx_limit_import,
'is_email_sending_enabled': current_app.config['CAN_SEND_EMAILS'],
'is_registration_enabled': self.is_registration_enabled, 'is_registration_enabled': self.is_registration_enabled,
'max_single_file_size': self.max_single_file_size, 'max_single_file_size': self.max_single_file_size,
'max_zip_file_size': self.max_zip_file_size, 'max_zip_file_size': self.max_zip_file_size,

View File

@ -0,0 +1,14 @@
import click
from fittrackee.migrations.commands import db_cli
from fittrackee.users.commands import users_cli
@click.group()
def cli() -> None:
"""FitTrackee Command Line Interface"""
pass
cli.add_command(db_cli)
cli.add_command(users_cli)

3
fittrackee/cli/app.py Normal file
View File

@ -0,0 +1,3 @@
from fittrackee import create_app
app = create_app(init_email=False)

View File

@ -12,7 +12,6 @@ else:
class BaseConfig: class BaseConfig:
"""Base configuration"""
DEBUG = False DEBUG = False
TESTING = False TESTING = False
@ -30,6 +29,7 @@ class BaseConfig:
UI_URL = os.environ.get('UI_URL') UI_URL = os.environ.get('UI_URL')
EMAIL_URL = os.environ.get('EMAIL_URL') EMAIL_URL = os.environ.get('EMAIL_URL')
SENDER_EMAIL = os.environ.get('SENDER_EMAIL') SENDER_EMAIL = os.environ.get('SENDER_EMAIL')
CAN_SEND_EMAILS = False
DRAMATIQ_BROKER = broker DRAMATIQ_BROKER = broker
TILE_SERVER = { TILE_SERVER = {
'URL': os.environ.get( 'URL': os.environ.get(
@ -43,40 +43,42 @@ class BaseConfig:
' contributors', ' contributors',
), ),
'DEFAULT_STATICMAP': ( 'DEFAULT_STATICMAP': (
os.environ.get('DEFAULT_STATICMAP', 'False') == 'True' os.environ.get('DEFAULT_STATICMAP', 'false').lower() == 'true'
), ),
'STATICMAP_SUBDOMAINS': os.environ.get('STATICMAP_SUBDOMAINS', ''),
} }
TRANSLATIONS_FOLDER = os.path.join(
current_app.root_path, 'emails/translations'
)
LANGUAGES = ['en', 'fr', 'de']
class DevelopmentConfig(BaseConfig): class DevelopmentConfig(BaseConfig):
"""Development configuration"""
DEBUG = True DEBUG = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SECRET_KEY = 'development key' SECRET_KEY = 'development key' # nosec
BCRYPT_LOG_ROUNDS = 4 BCRYPT_LOG_ROUNDS = 4
DRAMATIQ_BROKER_URL = os.getenv('REDIS_URL', 'redis://') DRAMATIQ_BROKER_URL = os.getenv('REDIS_URL', 'redis://')
class TestingConfig(BaseConfig): class TestingConfig(BaseConfig):
"""Testing configuration"""
DEBUG = True DEBUG = True
TESTING = True TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_TEST_URL') SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_TEST_URL')
SECRET_KEY = 'test key' SECRET_KEY = 'test key' # nosec
BCRYPT_LOG_ROUNDS = 4 BCRYPT_LOG_ROUNDS = 4
TOKEN_EXPIRATION_DAYS = 0 TOKEN_EXPIRATION_DAYS = 0
TOKEN_EXPIRATION_SECONDS = 3 TOKEN_EXPIRATION_SECONDS = 3
PASSWORD_TOKEN_EXPIRATION_SECONDS = 3 PASSWORD_TOKEN_EXPIRATION_SECONDS = 3
UPLOAD_FOLDER = '/tmp/fitTrackee/uploads'
UI_URL = 'http://0.0.0.0:5000' UI_URL = 'http://0.0.0.0:5000'
SENDER_EMAIL = 'fittrackee@example.com' SENDER_EMAIL = 'fittrackee@example.com'
class ProductionConfig(BaseConfig): class End2EndTestingConfig(TestingConfig):
"""Production configuration""" DRAMATIQ_BROKER_URL = os.getenv('REDIS_URL', 'redis://')
class ProductionConfig(BaseConfig):
DEBUG = False DEBUG = False
# https://docs.sqlalchemy.org/en/13/core/pooling.html#using-connection-pools-with-multiprocessing-or-os-fork # noqa # https://docs.sqlalchemy.org/en/13/core/pooling.html#using-connection-pools-with-multiprocessing-or-os-fork # noqa
SQLALCHEMY_ENGINE_OPTIONS = ( SQLALCHEMY_ENGINE_OPTIONS = (

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.f76e2e3d.js"></script><script defer="defer" src="/static/js/app.3c006379.js"></script><link href="/static/css/app.28b1f60f.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.7132edc6.js"></script><script defer="defer" src="/static/js/app.bf1d4e1c.js"></script><link href="/static/css/app.32d0ced1.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
#account-confirmation[data-v-785df978]{display:flex;flex-direction:column;align-items:center}#account-confirmation svg[data-v-785df978]{stroke:none;fill-rule:nonzero;fill:var(--app-color);filter:var(--svg-filter);width:100px}#account-confirmation .error-message[data-v-785df978]{font-size:1.1em;text-align:center;display:flex;flex-direction:column}@media screen and (max-width:1000px){#account-confirmation .error-message[data-v-785df978]{font-size:1em}}#email-update[data-v-8c2ec9ce]{display:flex;flex-direction:column;align-items:center}#email-update svg[data-v-8c2ec9ce]{stroke:none;fill-rule:nonzero;fill:var(--app-color);filter:var(--svg-filter);width:100px}#email-update .error-message[data-v-8c2ec9ce]{font-size:1.1em;text-align:center;display:flex;flex-direction:column}@media screen and (max-width:1000px){#email-update .error-message[data-v-8c2ec9ce]{font-size:1em}}#profile[data-v-05463732],#profile[data-v-05463732] .profile-form{display:flex;flex-direction:column}#profile[data-v-05463732] .profile-form hr{border-color:var(--card-border-color);border-width:1px 0 0 0}#profile[data-v-05463732] .profile-form .form-items{display:flex;flex-direction:column}#profile[data-v-05463732] .profile-form .form-items input{margin:5px 0}#profile[data-v-05463732] .profile-form .form-items select{height:35px;padding:5px 0}#profile[data-v-05463732] .profile-form .form-items ::v-deep(.custom-textarea) textarea{padding:5px}#profile[data-v-05463732] .profile-form .form-items .form-item{display:flex;flex-direction:column;padding:10px}#profile[data-v-05463732] .profile-form .form-items .birth-date{height:20px}#profile[data-v-05463732] .profile-form .form-buttons{display:flex;margin-top:10px;padding:10px 0;gap:10px}#user[data-v-af7007f4]{margin:auto;width:700px}@media screen and (max-width:1000px){#user[data-v-af7007f4]{width:100%;margin:0 auto 50px auto}}

View File

@ -1 +0,0 @@
#profile[data-v-163d82f7],#profile[data-v-163d82f7] .profile-form{display:flex;flex-direction:column}#profile[data-v-163d82f7] .profile-form hr{border-color:var(--card-border-color);border-width:1px 0 0 0}#profile[data-v-163d82f7] .profile-form .form-items{display:flex;flex-direction:column}#profile[data-v-163d82f7] .profile-form .form-items input{margin:5px 0}#profile[data-v-163d82f7] .profile-form .form-items select{height:35px;padding:5px 0}#profile[data-v-163d82f7] .profile-form .form-items ::v-deep(.custom-textarea) textarea{padding:5px}#profile[data-v-163d82f7] .profile-form .form-items .form-item{display:flex;flex-direction:column;padding:10px}#profile[data-v-163d82f7] .profile-form .form-items .birth-date{height:20px}#profile[data-v-163d82f7] .profile-form .form-buttons{display:flex;margin-top:10px;padding:10px 0;gap:10px}#user[data-v-10e7b479]{margin:auto;width:700px}@media screen and (max-width:1000px){#user[data-v-10e7b479]{width:100%;margin:0 auto 50px auto}}

View File

@ -1 +0,0 @@
#password-action-done[data-v-18334f6d]{display:flex;flex-direction:column;align-items:center}#password-action-done svg[data-v-18334f6d]{stroke:none;fill-rule:nonzero;fill:var(--app-color);filter:var(--svg-filter);width:100px}#password-action-done .password-message[data-v-18334f6d]{font-size:1.1em;text-align:center}@media screen and (max-width:1000px){#password-action-done .password-message[data-v-18334f6d]{font-size:1em}}#password-reset-request[data-v-68377e44] .card .card-content #user-form{width:100%}#password-reset[data-v-f5e39b60]{display:flex}#password-reset .container[data-v-f5e39b60]{display:flex;justify-content:center;width:50%}@media screen and (max-width:700px){#password-reset .container[data-v-f5e39b60]{width:100%;margin:0 auto 50px auto}}

View File

@ -0,0 +1 @@
#account-confirmation-email[data-v-66aca424]{display:flex;flex-direction:column}#account-confirmation-email .email-sent[data-v-66aca424]{display:flex;flex-direction:column;align-items:center}#account-confirmation-email .email-sent svg[data-v-66aca424]{stroke:none;fill-rule:nonzero;fill:var(--app-color);filter:var(--svg-filter);width:100px}#account-confirmation-email .email-sent .email-sent-message[data-v-66aca424]{font-size:1.1em;text-align:center}@media screen and (max-width:1000px){#account-confirmation-email .email-sent .email-sent-message[data-v-66aca424]{font-size:1em}}#account-confirmation-email[data-v-66aca424] .card .card-content #user-auth-form{margin-top:0}#account-confirmation-email[data-v-66aca424] .card .card-content #user-auth-form #user-form{width:100%}#account-confirmation[data-v-35aad344]{display:flex}#account-confirmation .container[data-v-35aad344]{display:flex;justify-content:center;width:50%}@media screen and (max-width:700px){#account-confirmation .container[data-v-35aad344]{width:100%}}#password-action-done[data-v-eac78356]{display:flex;flex-direction:column;align-items:center}#password-action-done svg[data-v-eac78356]{stroke:none;fill-rule:nonzero;fill:var(--app-color);filter:var(--svg-filter);width:100px}#password-action-done .password-message[data-v-eac78356]{font-size:1.1em;text-align:center}@media screen and (max-width:1000px){#password-action-done .password-message[data-v-eac78356]{font-size:1em}}#password-reset-request[data-v-68377e44] .card .card-content #user-form{width:100%}#password-reset[data-v-a1cc55c4]{display:flex}#password-reset .container[data-v-a1cc55c4]{display:flex;justify-content:center;width:50%}@media screen and (max-width:700px){#password-reset .container[data-v-a1cc55c4]{width:100%}}

View File

@ -1 +0,0 @@
.chart-menu[data-v-af15954c]{display:flex}.chart-menu .chart-arrow[data-v-af15954c],.chart-menu .time-frames[data-v-af15954c]{flex-grow:1;text-align:center}.chart-menu .chart-arrow[data-v-af15954c]{cursor:pointer}.sports-menu{display:flex;flex-wrap:wrap;padding:10px}.sports-menu label{display:flex;align-items:center;font-size:.9em;font-weight:400;min-width:120px;padding:10px}@media screen and (max-width:1000px){.sports-menu label{min-width:100px}}@media screen and (max-width:500px){.sports-menu label{min-width:20px}.sports-menu label .sport-label{display:none}}.sports-menu .sport-img{padding:3px;width:20px;height:20px}#user-statistics.stats-disabled[data-v-7d54529b]{opacity:.3;pointer-events:none}#user-statistics[data-v-7d54529b] .chart-radio{justify-content:space-around;padding:30px 10px 10px 10px}#statistics[data-v-0d93da6e]{display:flex;width:100%}#statistics .container[data-v-0d93da6e]{display:flex;flex-direction:column;width:100%}

View File

@ -0,0 +1 @@
.chart-menu[data-v-22d55de2]{display:flex}.chart-menu .chart-arrow[data-v-22d55de2],.chart-menu .time-frames[data-v-22d55de2]{flex-grow:1;text-align:center}.chart-menu .chart-arrow[data-v-22d55de2]{cursor:pointer}.sports-menu{display:flex;flex-wrap:wrap;padding:10px}.sports-menu label{display:flex;align-items:center;font-size:.9em;font-weight:400;min-width:120px;padding:10px}@media screen and (max-width:1000px){.sports-menu label{min-width:100px}}@media screen and (max-width:500px){.sports-menu label{min-width:20px}.sports-menu label .sport-label{display:none}}.sports-menu .sport-img{padding:3px;width:20px;height:20px}#user-statistics.stats-disabled[data-v-d693c7da]{opacity:.3;pointer-events:none}#user-statistics[data-v-d693c7da] .chart-radio{justify-content:space-around;padding:30px 10px 10px 10px}#statistics[data-v-2e341d4e]{display:flex;width:100%}#statistics .container[data-v-2e341d4e]{display:flex;flex-direction:column;width:100%}

File diff suppressed because one or more lines are too long

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