Merge branch 'master' into groups

# Conflicts:
#	docs/install.rst
#	requirements.txt
#	wger/core/apps.py
#	wger/core/templates/navigation.html
#	wger/gym/views/gym.py
#	wger/manager/api/views.py
#	wger/manager/apps.py
#	wger/manager/fixtures/test-workout-data.json
#	wger/manager/models.py
#	wger/manager/tests/test_workout.py
#	wger/manager/views/workout.py
#	wger/settings_global.py
#	wger/urls.py
This commit is contained in:
Roland Geider
2020-08-30 19:00:23 +02:00
583 changed files with 54448 additions and 54410 deletions

View File

@@ -1,4 +0,0 @@
{
"directory" : "wger/core/static/bower_components",
"interactive": false
}

4
.dockerignore Normal file
View File

@@ -0,0 +1,4 @@
venv
node_modules
**/__pycache__
*.egg-info

View File

@@ -11,18 +11,47 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
# Docstrings and comments use max_line_length = 79
[*.py]
max_line_length = 100
#
# Javascript
#
[*.js]
indent_size = 2
[.eslintignore]
[{.eslintrc,.eslintignore}]
indent_size = 2
#
# Python
#
[*.py]
max_line_length = 100
#
# JSON File
#
[*.json]
indent_size = 2
#
# YAML File
#
[*.yml]
indent_size = 2
#
# Structured text and Markdown
#
[*.md]
trim_trailing_whitespace = false
indent_size = 2
[*.rst]
indent_size = 4
#
# Makefiles
#
[{Makefile, makefile, GNUmakefile}]
indent_style = tab
indent_size = 4

View File

@@ -1,8 +0,0 @@
# Ignore the following files and directories
/docs/
/extras/
/gulpfile.js
/node_modules/
/wger/core/static/bower_components/
/wger/core/static/js/Sortable.min.js
/wger/node_modules/

15
.gitattributes vendored
View File

@@ -1,2 +1,13 @@
# Auto detect text files and perform LF normalization
* text=auto
# Bash scripts (e.g. in Docker) make problems when the line ending is not LF
* text eol=lf
# These files are binary and should be left untouched
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.ttf binary
*.woff binary
*.eot binary
*.pdf binary

40
.github/contributing.md vendored Normal file
View File

@@ -0,0 +1,40 @@
# Contributing to wger
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
Our goal is to build an awesome and flexible fitness and nutrition manager,
along with a comprehensive list of exercises and ingredients, all released
under a free license.
The following is a set of guidelines for contributing to wger
which is hosted in the wger-project Organization on GitHub.
These are mostly guidelines, not rules. As everywhere in life, use your
best judgment, and feel free to propose changes to this document
in a pull request.
## Questions
Are you just using the software and have a question or improvement?
* Ask it on the [gitter channel](https://gitter.im/wger-project/wger)
* or just [open an issue](https://github.com/wger-project/wger/issues)
## Issues
Describe the problem as well as you can. If useful, include any screenshots,
server logs or exceptions that you have access to and think might be relevant.
Include the git SHA1 if you have installed from source. If it's an enhancement,
describe a use-case or similar.
## Pull Requests
You want to contribute code? Awesome! Here are some tips:
* Make sure the tests are running (``python3 manage.py tests``)...
* ... and if you write new code, write new tests
* Lint the code with flake8 (``flake8 --config .github/linters/.flake8``)
and isort (``isort``)
* You can expect a response from a maintainer within a week, if you
havent heard anything by then, feel free to ping the thread.
Thanks!
-the wger Team

21
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@@ -1,5 +1,4 @@
{
"extends": "airbnb-base/legacy",
"env": {
"browser": true,
"jquery": true

15
.github/linters/.flake8 vendored Normal file
View File

@@ -0,0 +1,15 @@
[flake8]
# H101: Use TODO(NAME)
# W503: line break before binary operator
ignore = H101,W503
max-line-length = 100
exclude =
extras,
build,
dist,
yarn,
migrations,
settings.py,
docs,
urls.py : E501
apps.py : F401

597
.github/linters/.python-lint vendored Normal file
View File

@@ -0,0 +1,597 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-whitelist=
# Specify a score threshold to be exceeded before program exits with error.
fail-under=10
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=tests,migrations
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
jobs=0
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=import-error,
print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
duplicate-code,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[REPORTS]
# Python expression which should return a score less than or equal to 10. You
# have access to the variables 'error', 'warning', 'refactor', and 'convention'
# which contain the number of messages in each category, as well as 'statement'
# which is the total number of statements analyzed. This score is used by the
# global evaluation report (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages.
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit
[LOGGING]
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style=old
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=no
# This flag controls whether the implicit-str-concat should generate a warning
# on implicit string concatenation in sequences defined over several lines.
check-str-concat-over-line-jumps=no
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
# List of decorators that change the signature of a decorated function.
signature-mutators=
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[BASIC]
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style.
#argument-rgx=
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Bad variable names regexes, separated by a comma. If names match any regex,
# they will always be refused
bad-names-rgxs=
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
#class-attribute-rgx=
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style.
#class-rgx=
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style.
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names.
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style.
#function-rgx=
# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_
# Good variable names regexes, separated by a comma. If names match any regex,
# they will always be accepted
good-names-rgxs=
# Include a hint for the correct naming format with invalid-name.
include-naming-hint=no
# Naming style matching correct inline iteration names.
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
#inlinevar-rgx=
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style.
#method-rgx=
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style.
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style.
#variable-rgx=
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it work,
# install the python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains the private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to the private dictionary (see the
# --spelling-private-dict-file option) instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
# Regular expression of note tags to take in consideration.
#notes-rgx=
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module.
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
[DESIGN]
# Maximum number of arguments for function / method.
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in an if statement (see R0916).
max-bool-expr=5
# Maximum number of branch for function / method body.
max-branches=12
# Maximum number of locals for function / method body.
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body.
max-returns=6
# Maximum number of statements in function / method body.
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[IMPORTS]
# List of modules that can be imported at any level, not just the top level
# one.
allow-any-import-level=
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled).
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled).
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
# Couples of modules and preferred modules, separated by a comma.
preferred-modules=
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp,
__post_init__
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "BaseException, Exception".
overgeneral-exceptions=BaseException,
Exception

6
.github/linters/.stylelintrc.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"extends": "stylelint-config-standard",
"rules": {
"no-descending-specificity": null
}
}

18
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,18 @@
### Proposed Changes
-
-
-
### Please check that the PR fulfills these requirements
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] New python code has been linted with with flake8 (``flake8 --config .github/linters/.flake8``)
and isort (``isort``)
- [ ] Added yourself to AUTHORS.rst
### Other questions
* Does this PR introduce a breaking change such as a database migration? (i.e.
what changes might users need to make in their running application due to
this PR?)

54
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: "CodeQL"
on:
push:
branches: [master, ]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 1 * * 2'
jobs:
analyse:
name: Analyse
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

43
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Build and push Docker images
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build base image
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: wger/base
dockerfile: extras/docker/base/Dockerfile
tags: latest,2.0-dev
tag_with_ref: true
- name: Build dev image
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: wger/devel
dockerfile: extras/docker/development/Dockerfile
tags: latest,2.0-dev
tag_with_ref: true
- name: Build apache image
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: wger/apache
dockerfile: extras/docker/apache/Dockerfile
tags: latest,2.0-dev
tag_with_ref: true

56
.github/workflows/linter.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
###########################
###########################
## Linter GitHub Actions ##
###########################
###########################
name: Lint Code Base
#
# Documentation:
# https://help.github.com/en/articles/workflow-syntax-for-github-actions
#
################################################
# Trigger the workflow on push or pull request #
# but only for the master branch #
################################################
on:
push:
branches:
- master
pull_request:
branches:
- master
###############
# Set the Job #
###############
jobs:
build:
# Name the Job
name: Lint Code Base
# Set the agent to run on
runs-on: ubuntu-latest
##################
# Load all steps #
##################
steps:
##########################
# Checkout the code base #
##########################
- name: Checkout Code
uses: actions/checkout@v2
################################
# Run Linter against code base #
################################
- name: Lint Code Base
uses: docker://github/super-linter:v3.5.1
env:
VALIDATE_PYTHON_FLAKE8: true
VALIDATE_MD: true
VALIDATE_JAVASCRIPT_ES: true
VALIDATE_JSON: true
VALIDATE_DOCKER: true

31
.github/workflows/pypi-publish.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Upload Package to PyPI
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*

6
.gitignore vendored
View File

@@ -59,6 +59,8 @@ target/
# IDE
.idea/
# External Libraries
wger/core/static/bower_components
# External Libraries
wger/core/static/yarn
node_modules
venv

15
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,15 @@
---
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: v1.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: autopep8-wrapper
- id: check-yaml
- id: check-merge-conflict
- id: debug-statements
- id: flake8
- repo: git://github.com/detailyang/pre-commit-shell
sha: 1.0.2
hooks:
- id: shell-lint

View File

@@ -1,4 +1,8 @@
language: python
dist: bionic
services:
- postgresql
# Cache the pip files
cache:
@@ -8,60 +12,43 @@ cache:
- node_modules
- wger/node_modules
# Use container infrastructure
# http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/
sudo: false
# Python versions to test
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
- "3.7"
- "3.8"
node_js: 10
# Manually define here the combinations environment variables to test
# https://github.com/travis-ci/travis-ci/issues/1519
env:
- TEST_MOBILE=True DB=postgresql TRAVIS_NODE_VERSION="4"
- TEST_MOBILE=True DB=sqlite TRAVIS_NODE_VERSION="4"
- TEST_MOBILE=False DB=postgresql TRAVIS_NODE_VERSION="4"
- TEST_MOBILE=False DB=sqlite TRAVIS_NODE_VERSION="4"
- DB=postgresql
- DB=sqlite
# Install the application
install:
# Update nvm and set wanted Node version.
# We update nvm using the script method instead of git, which is selected
# automatically, as git won't work because the $HOME/.nvm is not a git
# repository and the directory is not empty.
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.4/install.sh | METHOD=script bash
- . $HOME/.nvm/nvm.sh
- nvm install $TRAVIS_NODE_VERSION
- nvm use $TRAVIS_NODE_VERSION
# Install requirements
- pip install -r requirements_devel.txt
- npm install
- python setup.py develop
- cd wger
- if [[ "$DB" = "postgresql" ]]; then pip install psycopg2; fi
# Setup application
- if [[ "$DB" = "sqlite" ]]; then invoke create_settings; fi
- if [[ "$DB" = "postgresql" ]]; then invoke create_settings --database-type postgresql; fi
- if [[ "$DB" = "sqlite" ]]; then wger create-settings; fi
- if [[ "$DB" = "postgresql" ]]; then wger create-settings --database-type postgresql; fi
# change back to the source folder
- cd ..
# Create test databases
before_script:
- if [[ "$DB" = "postgresq" ]]; then psql -c 'DROP DATABASE IF EXISTS test_wger;' -U postgres; fi
- if [[ "$DB" = "postgresql" ]]; then psql -c 'DROP DATABASE IF EXISTS test_wger;' -U postgres; fi
- if [[ "$DB" = "postgresql" ]]; then psql -c 'CREATE DATABASE test_wger;' -U postgres; fi
# Do the tests
script:
# Formatting
- pep8 wger
# Javascript linting
- gulp lint
# Regular application
- coverage run --source='.' ./manage.py test
- coverage run --source='.' ./manage.py test --parallel
# Code coverage
- coverage report

8
.tx/config Normal file
View File

@@ -0,0 +1,8 @@
[main]
host = https://www.transifex.com
[wger-workout-manager.application]
file_filter = wger/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
type = PO

2
.yarnrc Normal file
View File

@@ -0,0 +1,2 @@
# install modules here
--modules-folder wger/core/static/yarn/

View File

@@ -24,6 +24,7 @@ Developers
* Peter van der Does: https://github.com/petervanderdoes
* Malcolm Jones: https://github.com/DevloperMal
* Boniface Mwenda: https://github.com/andela-bmwenda
* Scott Peshak: https://github.com/speshak
Translators
-----------

View File

@@ -1,24 +1,21 @@
# Files in root folder
include README.rst
include AUTHORS.txt
include AGPL.txt
include CC-BY-SA.txt
include requirements.txt
include tasks.py
include requirements_devel.txt
# Application folder as well as extras
recursive-include extras *.*
recursive-include wger *.*
recursive-exclude wger *.pyc
recursive-exclude wger *.swp
recursive-exclude wger *~
include extras/docker/*/Dockerfile
# added by check_manifest.py
include *.rst
include *.txt
# Documentation
recursive-include docs *.bat
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs Makefile
recursive-include extras *.README
recursive-include extras *.conf
recursive-include extras *.csv
recursive-include extras *.py
recursive-include extras *.txt

View File

@@ -1,22 +1,21 @@
Thank you for downloading wger Workout Manager. wger (ˈɡɐ) is a free, open source web
application that manages your exercises and personal workouts, weight and diet
plans. It can also be used as a simple gym management utility, providing different
administrative roles (trainer, manager, etc.). It offers a REST API as well, for
easy integration with other projects and tools.
wger
====
It is written with python/django and uses jQuery and some D3js for charts.
wger (ˈɡɐ) Workout Manager is a free, open source web application that help
you manage your personal workouts, weight and diet plans and can also be used
as a simple gym management utility. It offers a REST API as well, for easy
integration with other projects and tools.
For more details and a live system, refer to the project's site: https://wger.de/
For a live system, refer to the project's site: https://wger.de/
Installation
============
These are the basic steps to install and run the application locally on a linux
These are the basic steps to install and run the application locally on a Linux
system. There are more detailed instructions, other deployment options as well
as an administration guide available at https://wger.readthedocs.io or locally
in your code repository in the docs folder (``make html`` to compile, then open
_build/index.html).
in your code repository in the docs folder.
Please consult the commands' help for further information and available
parameters.
@@ -25,7 +24,8 @@ parameters.
Docker
------
Useful to just try it out::
Useful to just try it out. Check the documentation on how to use the wger/devel
docker image or the docker-compose file for development::
docker run -ti --name wger.apache --publish 8000:80 wger/apache
@@ -43,19 +43,14 @@ and stable state.
::
$ sudo apt-get install python3-dev python-virtualenv nodejs nodejs-legacy npm libjpeg8-dev zlib1g-dev git
$ sudo apt-get install python3-dev nodejs npm git
$ sudo npm install -g yarn sass
On fedora 23
::
$ sudo dnf install python3-devel python-virtualenv nodejs npm libjpeg-turbo-devel zlib-devel git
Then install the python packages from pypi in the virtualenv::
$ virtualenv --python python3 venv-django
$ source venv-django/bin/activate
$ python3 -m venv venv-wger
$ source venv-wger/bin/activate
2) Start the application. This will download the required JS and CSS libraries
@@ -65,52 +60,18 @@ Then install the python packages from pypi in the virtualenv::
$ git clone https://github.com/wger-project/wger.git
$ cd wger
$ pip install -r requirements.txt # or requirements_devel.txt to develop
$ invoke create_settings \
--settings-path /home/wger/wger/settings.py \
--database-path /home/wger/wger/database.sqlite
$ invoke bootstrap_wger \
--settings-path /home/wger/wger/settings.py \
--no-start-server
$ pip install -r requirements.txt
$ python setup.py develop
$ wger create-settings --settings-path $(pwd)/settings.py --database-path $(pwd)/database.sqlite
$ wger bootstrap --settings-path $(pwd)/settings.py --no-start-server
$ python manage.py runserver
3) Log in as: **admin**, password **admin**
After the first run you can just use django's development server. You will
probably want to move the settings and sqlite files to your git folder, see
the comments in the documentation (development chapter) about this::
After the first run you just start django's development server::
$ python manage.py runserver
Docker images
~~~~~~~~~~~~~
Alternatively, there are docker images for development as well, ``wger/devel``
and ``wger/devel-fedora``. Both images contain an instance of the application
running with django's development server using a sqlite database and can be
used to quickly setup a development instance (vim and tmux are already
installed). The only difference is that devel has an ubuntu base image while
devel-fedora uses fedora.
::
$ docker run -ti --name wger.devel --publish 8000:8000 wger/devel
Then, *within the docker image*, activate the virtualenv
::
$ source ~/venv/bin/activate
and start the development server
::
$ python manage.py runserver 0.0.0.0:8000
Then just open http://localhost:8000 and log in as: **admin**, password **admin**
Stable version (from PyPI)
--------------------------
@@ -119,38 +80,45 @@ Stable version (from PyPI)
::
$ sudo apt-get install python3-dev python-virtualenv nodejs nodejs-legacy npm libjpeg8-dev zlib1g-dev
$ virtualenv venv-django
$ source venv-django/bin/activate
$ sudo apt-get install python3-dev nodejs npm git
$ sudo npm install -g yarn
$ python3 -m venv venv-wger
$ source venv-wger/bin/activate
$ pip install wger
2) Start the application. This will download the required JS and CSS libraries
and create a SQlite database and populate it with data on the first run.
Then, log in as: **admin**, password **admin**
::
$ wger bootstrap_wger
$ wger bootstrap
3) Log in as: **admin**, password **admin**
3) To start the installation again, just call wger start
::
$ wger start
Command line options
--------------------
You can get a list of all available commands by calling ``wger`` without any
arguments::
The available options for the ``wger`` command (if installed from PyPI) or
``invoke`` (if installed from source) are the following (use e.g. ``wger
<command>``::
Available tasks:
bootstrap Performs all steps necessary to bootstrap the application
config-location Returns the default location for the settings file and the data folder
create-or-reset-admin Creates an admin user or resets the password for an existing one
create-settings Creates a local settings file
load-fixtures Loads all fixtures
migrate-db Run all database migrations
start Start the application using django's built in webserver
bootstrap_wger Performs all steps necessary to bootstrap the application
config_location Returns the default location for the settings file and the data folder
create_or_reset_admin Creates an admin user or resets the password for an existing one
create_settings Creates a local settings file
load_fixtures Loads all fixtures
migrate_db Run all database migrations
start_wger Start the application using django's built in webserver
You can also get help on a specific command with ``wger --help <command>``.
Contact
=======
@@ -160,11 +128,9 @@ didn't behave as you expected. We can't fix what we don't know about, so please
report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway.
* **twitter:** https://twitter.com/wger_de
* **mailing list:** https://groups.google.com/group/wger / wger@googlegroups.com,
no registration needed
* **IRC:** channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger
* **gitter:** https://gitter.im/wger-project/wger
* **issue tracker:** https://github.com/wger-project/wger/issues
* **twitter:** https://twitter.com/wger_project
Sources
@@ -173,29 +139,28 @@ Sources
All the code and the content is freely available:
* **Main repository:** https://github.com/wger-project/wger
* **Mirror:** https://bitbucket.org/rolandgeider/wger
Donations
=========
wger is free software and will always remain that way, however if you want to
wger is free software and will always remain that way. However, if you want to
help and support the project you are more than welcome to donate an amount of
your choice.
.. image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UPMWQJY85JC5N
Licence
License
=======
The application is licenced under the Affero GNU General Public License 3 or
The application is licensed under the Affero GNU General Public License 3 or
later (AGPL 3+).
The initial exercise and ingredient data is licensed additionally under one of
the Creative Commons licenses, see the individual exercises for more details.
The documentation is released under a CC-BY-SA either version 4 of the License,
The documentation is released under a CC-BY-SA: either version 4 of the License,
or (at your option) any later version.
Some images where taken from Wikipedia, see the SOURCES file in their respective
Some images were taken from Wikipedia, see the SOURCES file in their respective
folders for more details.

View File

@@ -1,9 +1,113 @@
Changelog
=========
1.8 - IN DEVELOPMENT
--------------------
**2016-XX-XX**
2.0 - IN DEVELOPMENT
**2020-xx-xx**
Upgrade steps from 1.9:
* Update python libraries ``pip install -r requirements.txt``
* Install ``yarn`` and ``sass`` (e.g. ``sudo npm install -g yarn sass``)
* Update CSS and JS libraries ``yarn install``
* Compile the CSS ``sass wger/core/static/scss/main.scss:wger/core/static/yarn/bootstrap-compiled.css``
* Run migrations ``python manage.py migrate``
* Update static files (only production): ``python manage.py collectstatic``
* Subcommands for ``wger`` now use dashes in their names (i.e. create-settings instead of create_settings)
🚀 Features:
* Add nutrition diary to log the daily calories actually taken `#284`_
* Improved user experience, on desktop and mobile `#337`_
🐛 Bug Fixes:
* `#499`_, `#505`_, `#504`_
🧰 Maintenance:
* Improved docker and docker-compose images `#340`_
* Updated many libraries to last version (bootstrap, font awesome, etc.)
* Use yarn to download CSS/JS libraries
* Improvements to documentation (e.g. `#494`_)
.. _#284: https://github.com/wger-project/wger/issues/284
.. _#337: https://github.com/wger-project/wger/issues/337
.. _#340: https://github.com/wger-project/wger/issues/340
.. _#494: https://github.com/wger-project/wger/issues/494
.. _#499: https://github.com/wger-project/wger/issues/499
.. _#504: https://github.com/wger-project/wger/issues/504
.. _#505: https://github.com/wger-project/wger/issues/505
1.9
---
**2020-06-29**
Upgrade steps from 1.8:
* Django update to 3.x: ``pip install -r requirements.txt``
* Database upgrade: ``python manage.py migrate``
* Update static files (only production): ``python manage.py collectstatic``
New features:
* Allow users to enter their birthdate instead of just the age (thanks `@dtopal`_) `#332`_
* Work to ensure that mobile templates are used when appropriate
* Added optional S3 static asset hosting.
* Drop Python 2 support.
* Replaced django-mobile with django-user_agent (and some custom code)
This isn't as slick as django-mobile was, but it unblocks possible Django 2.x support.
* Update many dependencies to current versions.
Improvements:
* Improve look of weight graph (thanks `@alokhan`_) `#381`_
* Added password validation rules for more security
* Exercise image downloader checks only accepted exercises (thanks `@gmmoraes`_) `#363`_
* Use a native data type for the exercises' UUID (thanks `@gmmoraes`_) `#364`_
* Increase speed of testsuite by performing the tests in parallel (thanks `@Mbarak-Mbigo`_) `wger_vulcan/#6`_
* Update screen when adding an exercise to the workout while using set slider (thanks `@gmmoraes`_) `#374`_
* Work to slim docker image
* Download images at startup - If `DOWNLOAD_IMGS` environmental variable is set to `TRUE`
* Uninstall dev packages
* Update Ubuntu version used in docker container.
* Fixed a handful of hard coded static path references to use `static` taglib
* Updated tinymce theme for v5.
Other improvements and bugfixes: `#336`_, `#359`_,`#386`_, `#443`_
.. _@gmmoraes: https://github.com/gmmoraes
.. _@Mbarak-Mbigo: https://github.com/Mbarak-Mbigo
.. _@dtopal: https://github.com/dtopal
.. _wger_vulcan/#6: https://github.com/andela/wger_vulcan/pull/6
.. _#332: https://github.com/wger-project/wger/issues/332
.. _#336: https://github.com/wger-project/wger/issues/336
.. _#359: https://github.com/wger-project/wger/issues/359
.. _#363: https://github.com/wger-project/wger/issues/363
.. _#364: https://github.com/wger-project/wger/issues/364
.. _#374: https://github.com/wger-project/wger/issues/374
.. _#381: https://github.com/wger-project/wger/issues/381
.. _#386: https://github.com/wger-project/wger/issues/386
.. _#443: https://github.com/wger-project/wger/issues/443
1.8
---
**2017-04-05**
.. warning ::
There have been some changes to the installation procedure. Calling 'invoke'
on its own has been deprecated, you should use the 'wger' command (which
accepts the same options). Also some of these commands have been renamed:
* ``start_wger`` to ``wger``
* ``bootstrap_wger`` to ``bootstrap``
Upgrade steps from 1.7:
@@ -22,6 +126,7 @@ Upgrade steps from 1.7:
New languages:
* Norwegian (many thanks to Kjetil Elde `@w00p`_ `#304`_)
* French (many thanks to all translators)
New features:
@@ -43,6 +148,7 @@ Improvements:
* Give feedback when autocompleter didn't find any results `#293`_
* Make exercise names links to their detail page in training log pages `#350`_
* Better GUI consistency in modal dialogs (thanks `@jstoebel`_ ) `#274`_
* Cache is cleared when editing muscles (thanks `@RyanSept`_ `@pythonGeek`_ ) `#260`_
* Fields in workout log form are no longer required, making it possible to only log weight for certain exercises `#334`_
* New, more verbose, API endpoint for exercises, (thanks `@andela-bmwenda`_)
* The dashboard page was improved and made more user friendly `#201`_ (partly)
@@ -67,6 +173,7 @@ Other improvements and bugfixes: `#25`_, `#243`_, `#279`_, `#275`_, `#270`_,
.. _#243: https://github.com/wger-project/wger/issues/243
.. _#248: https://github.com/wger-project/wger/issues/248
.. _#247: https://github.com/wger-project/wger/issues/247
.. _#260: https://github.com/wger-project/wger/issues/260
.. _#263: https://github.com/wger-project/wger/issues/263
.. _#269: https://github.com/wger-project/wger/issues/269
.. _#272: https://github.com/wger-project/wger/issues/272
@@ -99,6 +206,8 @@ Other improvements and bugfixes: `#25`_, `#243`_, `#279`_, `#275`_, `#270`_,
.. _@alokhan: https://github.com/alokhan
.. _@w00p: https://github.com/w00p
.. _@andela-bmwenda: https://github.com/andela-bmwenda
.. _@RyanSept: https://github.com/RyanSept
.. _@pythonGeek: https://github.com/pythonGeek

View File

@@ -6,16 +6,7 @@ Coding Style Guide
Python
------
* Code according to PEP8
Check that the code is structured as per pep8 but with a maximum line
length of 100.
* Code for Python 3
While the application should remain compatible with python2, use django's
suggestion to mantain sanity: code for py3 and treat py2 as a backwards
compatibility requirement. If you need, you can use six.
Code according to PEP8, but with but with a maximum line length of 100.
Javascript
@@ -29,12 +20,8 @@ Javascript
* Functions called from Django templates need to start with ``wger``
Check Coding Style
==================
Automatic coding style checks
-----------------------------
The coding style is automatically check by Travis-CI. To manually check your
files you can run the following commands:
* Python: ``pep8 wger``
* Javascript: ``./node_modules/.bin/gulp lint-js`` (or just ``gulp lint-js`` if
you installed the node libraries globally on your system)
The coding style is automatically checked by GitHub actions after sending a
pull request.

View File

@@ -8,56 +8,47 @@ running application (to e.g. delete guest users, send emails, etc.).
Administration Commands
-----------------------
The application provides several administration and bootstraping commands. They
are all available with ``wger`` (if installed from PyPI) or ``invoke`` (if
installed from source)::
The application provides several administration and bootstraping commands that
can be passed to the ``wger`` command::
wger <command>
or ::
invoke <command>
Both versions behave the same but for simplicity, the invoke version will be used
in this manual.
You can get a list of all available commands with ``invoke --list`` or ``wger``.
While you can do this from any folder in the application, some of them (e.g.
``start_wger``) might only work from the root folder::
You can get a list of all available commands by calling ``wger`` without any
arguments::
Available tasks:
bootstrap_wger Performs all steps necessary to bootstrap the application
config_location Returns the default location for the settings file and the data folder
create_or_reset_admin Creates an admin user or resets the password for an existing one
create_settings Creates a local settings file
load_fixtures Loads all fixtures
migrate_db Run all database migrations
start_wger Start the application using django's built in webserver
bootstrap Performs all steps necessary to bootstrap the application
config-location Returns the default location for the settings file and the data folder
create-or-reset-admin Creates an admin user or resets the password for an existing one
create-settings Creates a local settings file
load-fixtures Loads all fixtures
migrate-db Run all database migrations
start Start the application using django's built in webserver
You can also get help on a specific command with ``invoke --help <command>``.
You can also get help on a specific command with ``wger --help <command>``.
.. note::
Most commands support a ``--settings-path`` command line option that sets the
settings file to use for the operation. If you use it, it is recommended to
use absolute paths, for example::
invoke bootstrap_wger --settings-path /path/to/development/wger/settings-test.py
wger bootstrap --settings-path /path/to/development/wger/settings-test.py
Bootstrap wger
~~~~~~~~~~~~~~
Bootstrap
~~~~~~~~~
Command: **bootstrap_wger**
Command: **bootstrap**
This command bootstraps the application: it creates a settings file, initialises
a sqlite database, loads all necessary fixtures for the application to work and
creates a default administrator user. While it can also work with e.g. a postgreSQL
database, you will need to create it yourself::
invoke bootstrap_wger
wger bootstrap
The most usual use-case is creating the settings file and the sqlite database to
their default locations, but you can set your own paths if you want e.g. start
@@ -65,7 +56,7 @@ developing on a branch that is going to change the database schema.
Usage::
Usage: inv[oke] [--core-opts] bootstrap_wger [--options] [other tasks here ...]
Usage: inv[oke] [--core-opts] bootstrap [--options] [other tasks here ...]
Docstring:
Performs all steps necessary to bootstrap the application
@@ -81,11 +72,11 @@ Usage::
Start wger
~~~~~~~~~~
Command: **start_wger**
Command: **start**
Starts an already installed application::
invoke start_wger
wger start
Please note that this is simply a comfort function and does not use any *magic*,
it simply calls django's development server and (optionally) opens a browser
@@ -94,7 +85,7 @@ is probably better.
Usage::
Usage: inv[oke] [--core-opts] start_wger [--options] [other tasks here ...]
Usage: inv[oke] [--core-opts] start [--options] [other tasks here ...]
Docstring:
Start the application using django's built in webserver
@@ -111,7 +102,7 @@ Usage::
Default locations
~~~~~~~~~~~~~~~~~
Command: **config_location**
Command: **config-location**
Information command that simply outputs the default locations for the settings
file as well as the data folder used for the sqlite database and the uploaded
@@ -121,21 +112,21 @@ files.
Create settings
~~~~~~~~~~~~~~~
Command: **create_settings**
Command: **create-settings**
Creates a new settings file based. If you call it without further arguments it
will create the settings in the default locations::
invoke create settings
wger create-settings
If you pass custom paths, it's recommended to use absolute paths::
invoke create_settings --settings-path /path/to/development/wger/settings-test.py --database-path /path/to/development/wger/database-test.sqlite
wger create-settings --settings-path /path/to/development/wger/settings-test.py --database-path /path/to/development/wger/database-test.sqlite
Usage::
Usage: inv[oke] [--core-opts] create_settings [--options] [other tasks here ...]
Usage: inv[oke] [--core-opts] create-settings [--options] [other tasks here ...]
Docstring:
Creates a local settings file
@@ -152,7 +143,7 @@ Usage::
Create or reset admin
~~~~~~~~~~~~~~~~~~~~~
Command: **create_or_reset_admin**
Command: **create-or-reset-admin**
Makes sure that the default administrator user exists. If you change the password
it is reset.
@@ -160,7 +151,7 @@ it is reset.
Usage::
Usage: inv[oke] [--core-opts] create_or_reset_admin [--options] [other tasks here ...]
Usage: inv[oke] [--core-opts] create-or-reset-admin [--options] [other tasks here ...]
Docstring:
Creates an admin user or resets the password for an existing one
@@ -173,7 +164,7 @@ Usage::
Migrate database
~~~~~~~~~~~~~~~~
Command: **migrate_db**
Command: **migrate-db**
Migrates the database schema. This command is called internally when installing
the application. The only need to call this explicitly is after installing a new
@@ -185,7 +176,7 @@ will happen.
Usage::
Usage: inv[oke] [--core-opts] migrate_db [--options] [other tasks here ...]
Usage: inv[oke] [--core-opts] migrate-db [--options] [other tasks here ...]
Docstring:
Run all database migrations
@@ -198,7 +189,7 @@ Usage::
Load all fixtures
~~~~~~~~~~~~~~~~~
Command: **load_fixtures**
Command: **load-fixtures**
Loads all fixture file with the default data. This data includes all data necessary
for the application to work such as:
@@ -215,7 +206,7 @@ as workouts are *not* reset with this, only the application data.
Usage::
Usage: inv[oke] [--core-opts] load_fixtures [--options] [other tasks here ...]
Usage: inv[oke] [--core-opts] load-fixtures [--options] [other tasks here ...]
Docstring:
Loads all fixtures

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# flake8: noqa
#
# wger Workout Manager documentation build configuration file, created by
# sphinx-quickstart on Mon Dec 1 22:22:02 2014.
@@ -47,16 +48,16 @@ master_doc = 'index'
# General information about the project.
project = u'wger Workout Manager'
copyright = u'2015, Roland Geider'
copyright = u'2020, Roland Geider'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.8'
version = '2.0'
# The full version, including alpha/beta/rc tags.
release = '1.8 alpha2'
release = '2.0 alpha'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -3,210 +3,63 @@
Development
===========
Requirements
------------
You can safely install from master, it is almost always in a usable
and stable state.
Virtual environment
~~~~~~~~~~~~~~~~~~~
::
$ python3 -m venv venv-wger
$ source venv-wger/bin/activate
Get the code
~~~~~~~~~~~~
::
The code is available on Github::
$ git clone https://github.com/wger-project/wger.git
Create a virtual environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's a best practise to create a Python virtual environment::
$ virtualenv --python python3 venv-wger
$ source venv-wger/bin/activate
$ cd wger
$ git clone https://github.com/wger-project/wger.git src
$ cd src
$ WGER_PATH=$(pwd)
Install Requirements
~~~~~~~~~~~~~~~~~~~~
To install the Python requirements::
::
$ pip install -r requirements_devel.txt
$ npm install -g yarn sass
$ python setup.py develop
Install NodeJS and npm::
Follow the instructions on the `NPM website <https://docs.npmjs
.com/getting-started/installing-node>`_ and make sure to use Node LTS (4
.x).
Install application
~~~~~~~~~~~~~~~~~~~
Install the npm modules::
$ npm install
This will download the required JS and CSS libraries and create a SQlite
database and populate it with data on the first run::
Install site
~~~~~~~~~~~~
To install the server::
$ invoke create_settings \
--settings-path /home/wger/wger/settings.py \
--database-path /home/wger/wger/database.sqlite
$ invoke bootstrap_wger \
--settings-path /home/wger/wger/settings.py \
$ wger create-settings \
--settings-path $WGER_PATH/settings.py \
--database-path $WGER_PATH/database.sqlite
$ wger bootstrap \
--settings-path $WGER_PATH/settings.py \
--no-start-server
You can of course also use other databases such as postgres or mariaDB. Create
a database and user and edit the DATABASES settings before calling bootstrap.
Take a look at the :ref:`prod_postgres` on apache on how that could look like.
Start the server
----------------
To start the server::
After the first run you can just use django's development server::
$ python manage.py runserver
That's it. You can log in with the default administator user:
That's it. You can log in with the default administrator user:
* **username**: admin
* **passsword**: admin
* **password**: admin
You can start the application again with the django server with
``python manage.py runserver``.
.. _tips:
Tips
----
Updating the code
~~~~~~~~~~~~~~~~~
When pulling updates from upstream there are a couple of things to consider.
These steps apply to all installation methods above.
Upgrading the database
``````````````````````
There are regularly changes and upgrades to the database schema (these may also
come from new versions of django or the installed dependencies). If you start
the development server and see a message that there are unapplied migrations,
just do ``python manage.py migrate --all``.
Downloading dependencies with Bower
```````````````````````````````````
Bower is used to download different JS and CSS libraries. If you update master
it is recommended that you first delete the existing libraries
(``rm wger/core/static/bower_components``) and then download the new versions
with::
$ python manage.py bower install
Some info about bower, during the bootstrap process bower is installed locally
to src/wger. If this didn't work and you get an error saying that bower is not
installed, you can manually install it by going to the project's root directory
and performing the step manually::
$ cd src/wger
$ npm install bower
Alternatively, you can manually set the path to the bower binary by editing
``BOWER_PATH`` (see ``wger/settings_global.py``).
Clearing the cache
``````````````````
Sometimes there are changes to the internal changes of the cached structures.
It is recommended that you just clear all the existing caches
``python manage.py clear-cache --clear-all``
Miscellaneous settings
~~~~~~~~~~~~~~~~~~~~~~
The following settings can be very useful during development (add to your
settings.py):
**Setting the email backend**
Use the console backend, all sent emails will be printed to it::
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Dummy data generator
~~~~~~~~~~~~~~~~~~~~
To properly test the different parts of the application for usability or
performance, it is often very useful to have some data to work with. For this
reason, there is a dummy data generator script in
extras/dummy_generator/generator.py. It allows you to generate entries for
users, gyms, workouts and logs. For detailed usage options do::
python generator.py --help
Or for options for, e.g. user generation::
python generator.py users --help
To get you started, you might want to invoke the script in the following way. This
will create 10 gyms and 300 users, randomly assigning them to a different gym. Each
user will have 20 workouts and each exercise in each workout 30 log entries::
python generator.py gyms 10
python generator.py users 300
python generator.py workouts 20
python generator.py logs 30
python generator.py sessions random
python generator.py weight 100
python generator.py nutrition 20
.. note::
All generated users have their username as password.
.. note::
While it is possible to generate hundreds of users, gyms are more restricted and
you will probably get duplicate names if you generate more than a dozen.
Selectively running tests
~~~~~~~~~~~~~~~~~~~~~~~~~
If you do a ``python manage.py test`` you will run the complete testsuite, and
this can take a while. You can control which tests will be executed like this.
Test only the tests in the 'core' app::
python manage.py test wger.core
Test only the tests in the 'test_user.py` file in the core app::
python manage.py test wger.core.tests.test_user
Test only the tests in 'StatusUserTestCase' in the file 'test_user.py` file in
the core app::
python manage.py test wger.core.tests.test_user.StatusUserTestCase
Using runserver_plus
~~~~~~~~~~~~~~~~~~~~
During development you can use ``runserver_plus`` instead of the default django
server as you can use an interactive debugger directly from the browser if an
exception occurs. It also accepts the same command line options. For this just
install the following packages::
pip install django_extensions werkzeug
python manage.py runserver_plus [options]
Contributing
------------
* **Send pull requests**: for new code you want to share, please send pull
requests in github. Sending patches by email or attaching them to an issue
means a lot more of work. It's recommended that you work on a feature branch
when working on something, specially when it's something bigger. While many
people insist on rebasing before sending a pull request, it's not necessary.
* **Run the tests**: wger is proud to have a test coverage of over 90%. When you
implement something new, don't forget to run the testsuite and write approriate
tests for the new code. If you use github, configure the awesome Travis CI,
there is already a .travis file in the sources.
* **Code according to the coding style**: :ref:`codingstyle`

View File

@@ -1,10 +1,31 @@
Docker
======
Docker images
=============
There are docker files available to quickly get a version of wger up and
running. They are all located under ``extras/docker`` if you want to build
them yourself.
Note that you need to build from the project's source folder, e.g::
docker build -f extras/docker/development/Dockerfile -t wger/devel .
docker build -f extras/docker/apache/Dockerfile --tag wger/apache .
Apache
------
This image runs the application using WSGI and apache.
Get the image::
docker pull wger/apache
Run a container and start the application::
docker run -ti --name wger.apache --publish 8000:80 wger/apache
Then just open http://localhost:8000 and log in as: **admin**, password **admin**
Development
-----------
@@ -12,10 +33,9 @@ Development
This image installs the application using virtualenv, uses a sqlite database
and serves it with django's development server.
Get the image::
First build the image::
docker build -t wger/devel .
docker pull wger/devel
Run a container and start the application::
@@ -23,12 +43,11 @@ Run a container and start the application::
(in docker) source ~/venv/bin/activate
(in docker) python manage.py runserver 0.0.0.0:8000
Now you can access the application on port 8000 of your host (probably just
http://localhost:8000).
Then just open http://localhost:8000 and log in as: **admin**, password **admin**
Depending on what you intend to do with it, you might want to map a local folder
to the container. This is interesting if e.g. you want to keep the wger source
code on your host machine and use docker only to serve it. Then you can do this::
As an alternative you might want to map a local folder to the container.
This is interesting if e.g. you want to keep the wger source code on
your host machine and use docker only to serve it. Then do this::
docker run -ti \
--name wger.test1 \
@@ -36,24 +55,7 @@ code on your host machine and use docker only to serve it. Then you can do this:
--volume /path/to/local/wger/:/home/wger/src \
wger/devel
It will mount the local path *on top* of the folder in the container, basically
exchanging one for the other. Please note that for this to work you need to
manually checkout the code to ``/path/to/local/wger/`` and create a settings file
as well.
It will mount the local path *on top* of the folder in the container. For this to
work you obviously need to manually checkout the code to ``/path/to/local/wger/``
and create a settings file as well.
Apache
------
This image runs the application using WSGI and apache.
First build the image::
docker build --tag wger/apache .
Run a container and start the application::
docker run -ti --name wger.apache --publish 8000:80 wger/apache
Now you can access the application on port 8000 of your host (probably just
http://localhost:8000).

View File

@@ -19,22 +19,27 @@ https://github.com/wger-project/wger
This documentation is intended for developers and administrators of the software.
Installation and development
----------------------------
Installation and administration
-------------------------------
.. toctree::
:maxdepth: 2
install
commands
installation
Development
-------------------------------
.. toctree::
tips_and_tricks
codingstyle
i18n
Administration guide
--------------------
.. toctree::
:maxdepth: 2
commands
settings
gym
@@ -53,11 +58,11 @@ Feel free to contact us if you found this useful or if there was something that
didn't behave as you expected (in this case you can also open a ticket on the
issue tracker).
* **twitter:** https://twitter.com/wger_de
* **gitter:** https://gitter.im/wger-project/wger
* **issue tracker:** https://github.com/wger-project/wger/issues
* **twitter:** https://twitter.com/wger_project
* **mailing list:** https://groups.google.com/group/wger / wger@googlegroups.com,
no registration needed
* **IRC:** channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger
* **issue tracker:** https://github.com/wger-project/wger/issues
Sources
@@ -85,11 +90,3 @@ folders for more details.
.. include the authors file from the root folder
.. include:: ../AUTHORS.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
* :ref:`modindex`

View File

@@ -1,59 +0,0 @@
.. _install:
Installation
============
This file gives a broad description of the necessary steps to install wger
on a debian based linux distribution. If your setup differs (e.g. in Red Hat
based distros the package names are slightly different) you will need to
change the steps but in the end, this is a regular django application so it
should run wherever django runs.
The application is compatible and regularly tested with
* sqlite, postgres
* python 2.7, 3.4 and 3.5
You might also want to take a look at the :ref:`other-changes` section for other
changes you might want to do to your local instance such as Terms of Service or
contact page.
.. note::
Please note that all the steps related to upgrading the database or
downloading external JS dependencies mentioned in the :ref:`tips` section
in the development page apply to all the installation options.
Base
----
These are the necessary packages for both development and production
(node and npm are only used to download JS and CSS libraries)::
sudo apt-get install nodejs nodejs-legacy npm git \
python-virtualenv python3-dev \
libjpeg8-dev zlib1g-dev libwebp-dev
.. note::
The application is developed with python 3, which these installation
instructions also use. If you want to use python 2.7, make sure you install
the appropriate packages (e.g. python-dev instead of python3-dev, etc.)!
Development
-----------
For development consult the :doc:`development` section.
Production
----------
For a more production-like setting with apache and mod-wsgi consult the
:doc:`production` chapter.
Docker
------
There are also docker images available, see the :doc:`docker` chapter.

39
docs/installation.rst Normal file
View File

@@ -0,0 +1,39 @@
.. _installation:
Installation
============
You can get a local instance of wger installed in a couple of minutes.
It is recommended to install a development instance or start a docker
image if you just want to try the application on your server or PC. All
the following steps are performed on a debian based linux distribution.
If your setup differs (e.g. in Red Hat based distros the package names are
slightly different) you will need to change the steps as appropriate.
The application is compatible and regularly tested with
* sqlite, postgres
* python 3.6, 3.7 and 3.8
After installation you might also want to take a look at the :ref:`other-changes` section for other
changes you might want to do to your local instance such as Terms of Service or
contact page.
.. note::
Please note that all the steps related to upgrading the database or
downloading external JS dependencies mentioned in the :ref:`tips` section
in the development page apply to all the installation options.
These are the necessary packages for both development and production::
sudo apt-get install nodejs npm git python3-dev python3-venv
.. toctree::
development
docker
production

View File

@@ -1,242 +1,242 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wgerWorkoutManager.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wgerWorkoutManager.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wgerWorkoutManager.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wgerWorkoutManager.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

View File

@@ -30,7 +30,7 @@ Configure apache to serve the application::
<VirtualHost *:80>
WSGIDaemonProcess wger python-path=/home/wger/src:/home/wger/venv/lib/python3.4/site-packages
WSGIDaemonProcess wger python-path=/home/wger/src python-home=/home/wger/venv
WSGIProcessGroup wger
WSGIScriptAlias / /home/wger/src/wger/wsgi.py
@@ -44,13 +44,13 @@ Configure apache to serve the application::
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
ErrorLog ${APACHE_LOG_DIR}/wger-error.log
CustomLog ${APACHE_LOG_DIR}/wger-access.log combined
</VirtualHost>
Apache has a problem when uploading files that have non-ASCII characters, e.g.
for exercise images. To avoid this, add to /etc/apache2/envvars (if there is
already an ``export LANG``, replace it)::
already an ``export LANG``, replace it) or set your system's locale::
export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'
@@ -63,14 +63,15 @@ Activate the settings and disable apache's default::
sudo service apache2 reload
Database
---------
--------
.. _prod_postgres:
postgreSQL
~~~~~~~~~~
Install the postgres server and create a database and a user::
sudo apt-get install postgresql postgresql-server-dev-9.3 # or appropriate version
sudo apt-get install postgresql postgresql-server-dev-12 # or appropriate version
su - postgres
createdb wger
psql wger -c "CREATE USER wger WITH PASSWORD 'wger'";
@@ -94,7 +95,7 @@ Application
Make a virtualenv for python and activate it::
virtualenv --python python3 /home/wger/venv
python3 -m venv /home/wger/venv
source /home/wger/venv/bin/activate
Create folders to collect all static resources and save uploaded files. The
@@ -111,10 +112,11 @@ Get the application::
git clone https://github.com/wger-project/wger.git /home/wger/src
cd /home/wger/src
npm install bower
pip install -r requirements.txt
npm install -g yarn sass
python setup.py develop
pip install psycopg2 # Only if using postgres
invoke create_settings \
wger create-settings \
--settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite
@@ -126,7 +128,7 @@ for the engine). Also set ``MEDIA_ROOT`` to ``/home/wger/media`` and
Run the installation script, this will download some CSS and JS libraries and
load all initial data::
invoke bootstrap_wger --settings-path /path/to/settings.py --no-start-server
wger bootstrap --settings-path /home/wger/src/settings.py --no-start-server
Collect all static resources::

147
docs/tips_and_tricks.rst Normal file
View File

@@ -0,0 +1,147 @@
.. _tips:
Tips and tricks
---------------
Updating the code
~~~~~~~~~~~~~~~~~
When pulling updates from upstream there are a couple of things to consider.
These steps apply to all installation methods above.
Upgrading the database
``````````````````````
There are regularly changes and upgrades to the database schema (these may also
come from new versions of django or the installed dependencies). If you start
the development server and see a message that there are unapplied migrations,
just do ``python manage.py migrate --all``.
Downloading JS and CSS libraries
````````````````````````````````
We use yarn to download the JS and CSS libraries. To update them just go to
the source and do ::
$ yarn install
This happens automatically during the bootstrap process.
Updating SASS files
```````````````````
After updating the SASS files, you need to compile them to regular CSS::
sass wger/core/static/scss/main.scss:wger/core/static/yarn/bootstrap-compiled.css
Clearing the cache
``````````````````
Sometimes there are changes to the internal changes of the cached structures.
It is recommended that you just clear all the existing caches
``python manage.py clear-cache --clear-all`` or just set the timeout to something
like one second (in settings.py::
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'wger-cache',
'TIMEOUT': 1
}
}
Miscellaneous settings
~~~~~~~~~~~~~~~~~~~~~~
The following settings can be very useful during development (add to your
settings.py):
**Setting the email backend**
Use the console backend, all sent emails will be printed to it::
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Dummy data generator
~~~~~~~~~~~~~~~~~~~~
To properly test the different parts of the application for usability or
performance, it is often very useful to have some data to work with. For this
reason, there is a dummy data generator script in
extras/dummy_generator/generator.py. It allows you to generate entries for
users, gyms, workouts and logs. For detailed usage options do::
python generator.py --help
Or for options for, e.g. user generation::
python generator.py users --help
To get you started, you might want to invoke the script in the following way. This
will create 10 gyms and 300 users, randomly assigning them to a different gym. Each
user will have 20 workouts and each exercise in each workout 30 log entries::
python generator.py gyms 10
python generator.py users 300
python generator.py workouts 20
python generator.py logs 30
python generator.py sessions random
python generator.py weight 100
python generator.py nutrition 20
.. note::
All generated users have their username as password.
.. note::
While it is possible to generate hundreds of users, gyms are more restricted and
you will probably get duplicate names if you generate more than a dozen.
Selectively running tests
~~~~~~~~~~~~~~~~~~~~~~~~~
If you do a ``python manage.py test`` you will run the complete testsuite, and
this can take a while. You can control which tests will be executed like this.
Test only the tests in the 'core' app::
python manage.py test wger.core
Test only the tests in the 'test_user.py` file in the core app::
python manage.py test wger.core.tests.test_user
Test only the tests in 'StatusUserTestCase' in the file 'test_user.py` file in
the core app::
python manage.py test wger.core.tests.test_user.StatusUserTestCase
Using runserver_plus
~~~~~~~~~~~~~~~~~~~~
During development you can use ``runserver_plus`` instead of the default django
server as you can use an interactive debugger directly from the browser if an
exception occurs. It also accepts the same command line options. For this just
install the following packages::
pip install django_extensions werkzeug
python manage.py runserver_plus [options]
Contributing
------------
* **Send pull requests**: for new code you want to share, please send pull
requests in github. Sending patches by email or attaching them to an issue
means a lot more of work. It's recommended that you work on a feature branch
when working on something, specially when it's something bigger. While many
people insist on rebasing before sending a pull request, it's not necessary.
* **Run the tests**: wger is proud to have a test coverage of over 90%. When you
implement something new, don't forget to run the testsuite and write approriate
tests for the new code. If you use github, configure the awesome Travis CI,
there is already a .travis file in the sources.
* **Code according to the coding style**: :ref:`codingstyle`

View File

@@ -1,27 +1,28 @@
# -*- coding: iso-8859-15 -*-
'''
# -*- coding: utf-8 -*-
# flake8: noqa
"""
Simple FunkLoad test
'''
"""
import unittest
from random import random
from funkload.FunkLoadTestCase import FunkLoadTestCase
class Simple(FunkLoadTestCase):
'''
"""
This test uses the configuration file Simple.conf.
'''
"""
def setUp(self):
'''
"""
Setting up test.
'''
"""
self.server_url = self.conf_get('main', 'url')
def test_simple(self):
# The description should be set in the configuration file
server_url = self.server_url
# Exercises
# Exercises
self.get(server_url + '/en/exercise/overview/', description='Get exercise overview')
self.get(server_url + '/en/exercise/muscle/overview/', description='Get muscle overview')
self.get(server_url + '/de/exercise/79/view/', description='Get exercise page')

View File

@@ -1,55 +1,109 @@
#
# A wger installation under apache with WSGI
#
# Note: you MUST build this image from the projec's root!
# docker build -f extras/docker/apache/Dockerfile --tag wger/apache .
#
# Please consult the documentation for usage
# docker build --tag wger/apache .
# docker run -ti --name wger.apache --publish 8000:80 wger/apache
#
# To stop the container:
# sudo docker container stop wger.apache
#
# To start developing again
# sudo docker container start --attach wger.apache
#
FROM wger/base
##########
# Builder
##########
FROM ubuntu:20.04 as builder
MAINTAINER Roland Geider <roland@geider.net>
EXPOSE 80
# Install dependencies
RUN apt-get install -y apache2 libapache2-mod-wsgi-py3
# Configure apache
RUN a2dissite 000-default.conf
ADD wger.conf /etc/apache2/sites-available/
RUN a2ensite wger
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
build-essential \
python3-dev \
python3-pip \
python3-wheel \
git \
&& rm -rf /var/lib/apt/lists/*
# Set up the application
COPY requirements* ./
RUN pip3 wheel --no-cache-dir --wheel-dir /usr/src/app/wheels -r requirements_devel.txt
########
# Final
########
FROM wger/base:2.0-dev
LABEL maintainer="Roland Geider <roland@geider.net>"
ARG DOCKER_DIR=./extras/docker/apache
EXPOSE 80
# Install dependencies
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
apache2 \
cron \
libapache2-mod-wsgi-py3 \
&& rm -rf /var/lib/apt/lists/*
# Configure apache
COPY ${DOCKER_DIR}/wger.conf /etc/apache2/sites-available/
RUN a2dissite 000-default.conf \
&& a2enmod headers \
&& a2ensite wger \
&& echo "ServerName localhost" >> /etc/apache2/conf-available/fqdn.conf \
&& a2enconf fqdn \
&& usermod -G wger www-data
# Configure cron
COPY ${DOCKER_DIR}/crontab /etc/cron.d/wger
COPY ${DOCKER_DIR}/venvwrapper /home/wger/venvwrapper
COPY ${DOCKER_DIR}/entrypoint.sh /home/wger/entrypoint.sh
RUN chmod 0644 /etc/cron.d/wger \
&& chmod +x /home/wger/venvwrapper /home/wger/entrypoint.sh \
&& touch /var/log/cron.log
COPY --from=builder /usr/src/app/wheels /wheels
COPY --chown=wger:www-data . /home/wger/src
# Set up the application
RUN ln -s /home/wger/static/CACHE /var/www
USER wger
RUN git clone https://github.com/wger-project/wger.git /home/wger/src
WORKDIR /home/wger/src
RUN virtualenv --python python3 /home/wger/venv
#RUN git clone https://github.com/wger-project/wger.git
RUN python3 -m venv /home/wger/venv
RUN . /home/wger/venv/bin/activate \
&& pip install --upgrade pip \
&& pip install -r requirements.txt \
&& invoke create_settings \
&& pip install wheel \
&& pip install --no-cache /wheels/* \
&& python setup.py develop \
&& wger create-settings \
--settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite \
&& invoke bootstrap_wger \
&& wger bootstrap \
--settings-path /home/wger/src/settings.py \
--no-start-server
# Change permissions of some files and folders so the apache process
# can access them.
RUN chmod o+w -R ~/db/ \
&& . /home/wger/venv/bin/activate \
&& mkdir ~/static \
&& mkdir ~/media \
&& chmod o+w ~/media \
RUN mkdir -p ~/static/CACHE ~/media \
&& ln -s /home/wger/static/CACHE /home/wger/src/CACHE \
&& chmod g+w /home/wger/static/CACHE \
&& sed -i "/^MEDIA_ROOT/c\MEDIA_ROOT='\/home\/wger\/media'" settings.py \
&& python manage.py download-exercise-images \
&& echo STATIC_ROOT=\'/home/wger/static\' >> settings.py \
&& python manage.py collectstatic --noinput
&& echo STATIC_ROOT=\'/home/wger/static\' >> settings.py
USER root
RUN apt-get remove build-essential -y \
&& apt autoremove -y \
&& chown www-data:www-data -R /home/wger/db
ENTRYPOINT ["/usr/sbin/apache2ctl"]
CMD ["-D", "FOREGROUND"]
ENTRYPOINT ["/home/wger/entrypoint.sh"]

View File

@@ -18,7 +18,25 @@ play around. To start it:
```docker run -ti --name wger.apache --publish 8000:80 wger/apache```
Then just open http://localhost:8000 and log in as: **admin**, password **admin**
Then just open <http://localhost:8000> and log in as: **admin**, password **admin**
To stop the container:
```sudo docker container stop wger.apache```
To start developing again:
```sudo docker container start --attach wger.apache```
Building
--------
If you build this yourself, keep in mind that you **must** build from the
project root!
```docker build -f extras/docker/apache/Dockerfile --tag wger/apache .```
Contact
-------
@@ -28,19 +46,17 @@ didn't behave as you expected. We can't fix what we don't know about, so please
report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway.
* twitter: https://twitter.com/wger_de
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger
* issue tracker: https://github.com/wger-project/wger/issues
* gitter: <https://gitter.im/wger-project/wger>
* issue tracker: <https://github.com/wger-project/wger/issues>
* twitter: <https://twitter.com/wger_project>
* mailing list: <https://groups.google.com/group/wger> / wger@googlegroups.com, no registration needed
Sources
-------
All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger
* Mirror: https://bitbucket.org/rolandgeider/wger
* Main repository: <https://github.com/wger-project/wger>
Licence
-------

View File

@@ -0,0 +1,6 @@
# wger cron jobs
0 5 * * * wger /home/wger/venvwrapper email-reminders
15 5 * * * wger /home/wger/venvwrapper email-weight-reminders
30 5 * * * wger /home/wger/venvwrapper inactive-members
42 4 * * * wger /home/wger/venvwrapper delete-temp-users
# Don't remove the empty line at the end of this file. It is required to run the cron job

View File

@@ -0,0 +1,14 @@
#!/bin/sh
/home/wger/venvwrapper migrate
if [ "${DOWNLOAD_IMGS}" = "TRUE" ]; then
/home/wger/venvwrapper download-exercise-images
chmod -R g+w ~wger/media
fi
/home/wger/venvwrapper collectstatic --no-input
/home/wger/venvwrapper compress --force
chown www-data:www-data -R /home/wger/static
/usr/sbin/apache2ctl -D FOREGROUND

View File

@@ -0,0 +1,5 @@
#!/bin/bash
. /home/wger/venv/bin/activate
python /home/wger/src/manage.py "$@"

View File

@@ -6,20 +6,26 @@
<VirtualHost *:80>
WSGIDaemonProcess wger python-path=/home/wger/src:/home/wger/venv/lib/python3.4/site-packages
WSGIDaemonProcess wger python-path=/home/wger/src python-home=/home/wger/venv
WSGIProcessGroup wger
WSGIScriptAlias / /home/wger/src/wger/wsgi.py
WSGIPassAuthorization On
Alias /static/ /home/wger/static/
<Directory /home/wger/static>
Require all granted
Require all granted
Header set Cache-Control "max-age=604800, public"
</Directory>
Alias /media/ /home/wger/media/
<Directory /home/wger//media>
Require all granted
<Directory /home/wger/media>
Require all granted
Header set Cache-Control "max-age=604800, public"
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
ErrorLog ${APACHE_LOG_DIR}/wger-error.log
CustomLog ${APACHE_LOG_DIR}/wger-access.log combined
</VirtualHost>
ServerSignature Off
ServerTokens Prod

View File

@@ -8,17 +8,34 @@
# docker build --tag wger/base .
#
FROM ubuntu:16.04
FROM ubuntu:20.04
MAINTAINER Roland Geider <roland@geider.net>
LABEL maintainer="Roland Geider <roland@geider.net>"
# Install dependencies
RUN apt-get update;\
apt-get install -y nodejs nodejs-legacy npm git \
python-virtualenv python3-dev \
libjpeg8-dev zlib1g-dev libwebp-dev \
sudo
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
git \
locales \
nodejs \
npm \
python3-venv \
python3-pip \
sqlite3 \
netcat-openbsd \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g yarn sass \
&& locale-gen en_US.UTF-8
# Environmental variables
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Add wger user
RUN adduser wger --disabled-password --gecos ""
RUN echo "wger ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/wger

View File

@@ -3,7 +3,7 @@ Development image for wger - Base image
This is the base image for some of the other wger images and offers no
functionality, it's only use is to provide some common dependencies.
If you want to develop, try either ``wger/devel`` oder ``wger/devel-fedora``.
If you want to develop, try ``wger/devel``.
Contact
@@ -14,18 +14,17 @@ didn't behave as you expected. We can't fix what we don't know about, so please
report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway.
* twitter: https://twitter.com/wger_de
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger
* issue tracker: https://github.com/wger-project/wger/issues
* gitter: <https://gitter.im/wger-project/wger>
* issue tracker: <https://github.com/wger-project/wger/issues>
* twitter: <https://twitter.com/wger_project>
* mailing list: <https://groups.google.com/group/wger> / wger@googlegroups.com, no registration needed
Sources
-------
All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger
* Mirror: https://bitbucket.org/rolandgeider/wger
* Main repository: <https://github.com/wger-project/wger>
Licence
-------

View File

@@ -0,0 +1,92 @@
# Development image for wger
Thank you for downloading wger Workout Manager. wger (ˈɡɐ) is a free, open
source web application that manages your exercises and personal workouts, weight
and diet plans. It can also be used as a simple gym management utility, providing
different administrative roles (trainer, manager, etc.). It offers a REST API
as well, for easy integration with other projects and tools.
## Usage
This docker-compose file starts up a development environment with django's
development server, postgres as a database and redis for caching and saving
the sessions. It binds your current code checkout into the volume, if you
don't want or have one, use the wger/apache image, it is self-contained.
### 1 - Start all services
To start all services:
docker-compose -f extras/docker/compose/docker-compose.yml up
Then open <http://localhost:8000> and log in as: **admin**, password **admin**
### 2 - Lifecycle Management
To stop all services issue a stop command, this will preserve all containers
and volumes:
docker-compose -f extras/docker/compose/docker-compose.yml stop
To start everything up again:
docker-compose -f extras/docker/compose/docker-compose.yml start
To remove all containers (except for the postgres volume)
docker-compose -f extras/docker/compose/docker-compose.yml down
To view the application's log:
docker-compose -f extras/docker/compose/docker-compose.yml logs -f
### 2 - Other commands
You might need to issue other commands or do other manual work in the container,
e.g.
docker-compose -f extras/docker/compose/docker-compose.yml exec web yarn install
docker-compose -f extras/docker/compose/docker-compose.yml exec --user root web /bin/bash
## Building
If you want to build this yourself, keep in mind that you **must** build from the
project root. Make sure the wger/devel image is available locally as well:
docker-compose -f extras/docker/compose/docker-compose.yml build.
## Contact
Feel free to contact us if you found this useful or if there was something that
didn't behave as you expected. We can't fix what we don't know about, so please
report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway.
* gitter: <https://gitter.im/wger-project/wger>
* issue tracker: <https://github.com/wger-project/wger/issues>
* twitter: <https://twitter.com/wger_project>
* mailing list: <https://groups.google.com/group/wger> / wger@googlegroups.com, no registration needed
## Sources
All the code and the content is freely available:
* Main repository: <https://github.com/wger-project/wger>
## Licence
The application is licenced under the Affero GNU General Public License 3 or
later (AGPL 3+).
The initial exercise and ingredient data is licensed additionally under one of
the Creative Commons licenses, see the individual exercises for more details.
The documentation is released under a CC-BY-SA either version 4 of the License,
or (at your option) any later version.
Some images where taken from Wikipedia, see the SOURCES file in their respective
folders for more details.

View File

@@ -0,0 +1,16 @@
# Database
DJANGO_DB_ENGINE=django.db.backends.postgresql
DJANGO_DB_DATABASE=wger
DJANGO_DB_USER=wger
DJANGO_DB_PASSWORD=wger
DJANGO_DB_HOST=db
DJANGO_DB_PORT=5432
# Cache
DJANGO_CACHE_BACKEND=django_redis.cache.RedisCache
DJANGO_CACHE_LOCATION=redis://cache:6379/1
DJANGO_CACHE_TIMEOUT=100
DJANGO_CACHE_CLIENT_CLASS=django_redis.client.DefaultClient
DJANGO_MEDIA_ROOT=/home/wger/media

View File

@@ -0,0 +1,36 @@
version: '3.7'
services:
web:
image: wger/devel:2.0-dev
volumes:
- type: bind
source: ../../../
target: /home/wger/src/
ports:
- 8000:8000
env_file:
- ./dev.env
depends_on:
- db
- cache
db:
image: postgres:12.0-alpine
volumes:
- wger-postgres-data:/var/lib/postgresql/data/
expose:
- 5432
environment:
- POSTGRES_USER=wger
- POSTGRES_PASSWORD=wger
- POSTGRES_DB=wger
cache:
restart: always
image: redis:latest
expose:
- 6379
volumes:
wger-postgres-data:

View File

@@ -1,57 +0,0 @@
#
# Docker image for wger development on a fedora base image
#
# Please consult the documentation for usage
# docker build -t wger/devel-fedora .
# docker run -ti --name wger.devel-fedora --publish 8000:8000 wger/devel-fedora
# (in docker) source ~/venv/bin/activate
# (in docker) python manage.py runserver 0.0.0.0:8000
#
#
FROM fedora:24
MAINTAINER Roland Geider <roland@geider.net>
# Install dependencies
RUN dnf update;\
dnf install -y python3-devel python-virtualenv \
nodejs npm libjpeg-turbo-devel zlib-devel git \
tmux sudo redhat-rpm-config gcc python-imaging
# Add wger user
RUN adduser wger
RUN echo "wger ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/wger
EXPOSE 8000
# Set up the application
USER wger
RUN git clone https://github.com/wger-project/wger.git /home/wger/src
WORKDIR /home/wger/src
RUN virtualenv --python python3 /home/wger/venv
RUN . /home/wger/venv/bin/activate \
&& pip install --upgrade pip \
&& pip install -r requirements_devel.txt \
&& invoke create_settings \
--settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite \
&& invoke bootstrap_wger \
--settings-path /home/wger/src/settings.py \
--no-start-server
# Install node modules for JS linting and download the exercise images
#
# Note: it seems there are problems with node and docker, so it's necessary
# to delete the node_modules folder and install everything again
# -> https://github.com/npm/npm/issues/9863
# -> https://github.com/npm/npm/issues/13306
RUN rm -r node_modules \
&& npm install bower \
&& npm install \
&& mkdir ~/media \
&& sed -i "/^MEDIA_ROOT/c\MEDIA_ROOT='\/home\/wger\/media'" settings.py \
&& . /home/wger/venv/bin/activate \
&& python manage.py download-exercise-images
CMD ["/bin/bash"]

View File

@@ -1,65 +0,0 @@
Development image for wger - Fedora based
=========================================
Thank you for downloading wger Workout Manager. wger (ˈɡɐ) is a free, open
source web application that manages your exercises and personal workouts, weight
and diet plans. It can also be used as a simple gym management utility, providing
different administrative roles (trainer, manager, etc.). It offers a REST API
as well, for easy integration with other projects and tools.
It is written with python/django and uses jQuery and some D3js for charts.
Installation
------------
This docker image contains an instance of the application running with django's
development server using a sqlite database. It can be used to quickly setup a
development instance (vim and tmux are already installed):
```docker run -ti --name wger.devel-fedora --publish 8000:8000 wger/devel-fedora```
Then, *within the docker image*, activate the virtualenv
```source ~/venv/bin/activate```
and start the development server
```python manage.py runserver 0.0.0.0:8000```
Then just open http://localhost:8000 and log in as: **admin**, password **admin**
Contact
-------
Feel free to contact us if you found this useful or if there was something that
didn't behave as you expected. We can't fix what we don't know about, so please
report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway.
* twitter: https://twitter.com/wger_de
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger
* issue tracker: https://github.com/wger-project/wger/issues
Sources
-------
All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger
* Mirror: https://bitbucket.org/rolandgeider/wger
Licence
-------
The application is licenced under the Affero GNU General Public License 3 or
later (AGPL 3+).
The initial exercise and ingredient data is licensed additionally under one of
the Creative Commons licenses, see the individual exercises for more details.
The documentation is released under a CC-BY-SA either version 4 of the License,
or (at your option) any later version.
Some images where taken from Wikipedia, see the SOURCES file in their respective
folders for more details.

View File

@@ -0,0 +1,80 @@
#
# Docker image for wger development:
#
# This image uses a virtual environment, which is not necessary in a docker
# image and is more or less intented to check that the installation instructions
# for a local develoment are up-to-date
#
# Please consult the documentation for usage
#
# Note: you MUST build this image from the projec's root!
# docker build -f extras/docker/development/Dockerfile --tag wger/devel .
#
# Run the container:
# docker run -ti --publish 8000:8000 --name wger.devel wger/devel
# (in docker) source ~/venv/bin/activate
# (in docker) python manage.py download-exercise-images (optional, may take some time)
# (in docker) python manage.py runserver 0.0.0.0:8000
#
# Alternatively, you can bind the local checkout into the container:
# docker run -ti -v /path/to/this/checkout:/home/wger/src --name wger.devel --publish 8000:8000 wger/devel
#
#
# To stop the container:
# sudo docker container stop wger.devel
#
# To start developing again
# sudo docker container start --attach wger.devel
#
##########
# Builder
##########
FROM ubuntu:20.04 as builder
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
build-essential \
python3-dev \
python3-pip \
git \
&& rm -rf /var/lib/apt/lists/*
# Set up the application
COPY . .
RUN pip3 install wheel \
&& pip3 wheel --no-cache-dir --wheel-dir /usr/src/app/wheels -r requirements_devel.txt
########
# Final
########
FROM wger/base:2.0-dev
LABEL maintainer="Roland Geider <roland@geider.net>"
ARG DOCKER_DIR=./extras/docker/development
EXPOSE 8000
# Set up the application
USER wger
COPY --chown=wger:wger . /home/wger/src
COPY --from=builder /usr/src/app/wheels /wheels
#RUN git clone https://github.com/wger-project/wger.git /home/wger/src
WORKDIR /home/wger/src
RUN python3 -m venv /home/wger/venv
RUN . /home/wger/venv/bin/activate \
&& pip install --upgrade pip \
&& pip install --no-cache /wheels/* \
&& python setup.py develop \
&& wger create-settings \
--settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite \
&& wger bootstrap \
--settings-path /home/wger/src/settings.py \
--no-start-server
# Download the exercise images
RUN mkdir ~/media \
&& sed -i "/^MEDIA_ROOT/c\MEDIA_ROOT='\/home\/wger\/media'" settings.py
CMD ["/bin/bash"]

View File

@@ -1,52 +1,60 @@
#
# Docker image for wger development
#
# Please consult the documentation for usage
# docker build -t wger/devel .
# docker run -ti --name wger.devel --publish 8000:8000 wger/devel
# (in docker) source ~/venv/bin/activate
# (in docker) python manage.py runserver 0.0.0.0:8000
# Please consult the README for usage
#
# Note: you MUST build this image from the projec's root!
# docker build -f extras/docker/development/Dockerfile --tag wger/devel .
#
# Run the container:
# docker run -ti -v /path/to/this/checkout:/home/wger/src --name wger.devel --publish 8000:8000 wger/devel
##########
# Builder
##########
FROM ubuntu:20.04 as builder
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
build-essential \
python3-dev \
python3-pip \
python3-wheel \
git \
&& rm -rf /var/lib/apt/lists/*
# Build the necessary python wheels
COPY requirements* ./
RUN pip3 wheel --no-cache-dir --wheel-dir /wheels -r requirements_devel.txt
FROM wger/base
MAINTAINER Roland Geider <roland@geider.net>
########
# Final
########
FROM wger/base:2.0-dev
LABEL maintainer="Roland Geider <roland@geider.net>"
ARG DOCKER_DIR=./extras/docker/development
EXPOSE 8000
# Install dependencies
RUN apt-get install -y vim tmux sqlite3
# Set up the application
USER wger
RUN git clone https://github.com/wger-project/wger.git /home/wger/src
WORKDIR /home/wger/src
RUN virtualenv --python python3 /home/wger/venv
RUN . /home/wger/venv/bin/activate \
&& pip install --upgrade pip \
&& pip install -r requirements_devel.txt \
&& invoke create_settings \
--settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite \
&& invoke bootstrap_wger \
--settings-path /home/wger/src/settings.py \
--no-start-server
COPY --chown=wger:wger . /home/wger/src
COPY --from=builder /wheels /wheels
COPY ${DOCKER_DIR}/settings.py /home/wger/src
COPY ${DOCKER_DIR}/settings.py /tmp/
COPY ${DOCKER_DIR}/entrypoint.sh /home/wger/entrypoint.sh
RUN chmod +x /home/wger/entrypoint.sh
RUN pip3 install --no-cache /wheels/* \
&& pip3 install psycopg2-binary \
&& pip3 install django-redis \
&& python3 setup.py develop
# Install node modules for JS linting and download the exercise images
#
# Note: it seems there are problems with node and docker, so it's necessary
# to delete the node_modules folder and install everything again
# -> https://github.com/npm/npm/issues/9863
# -> https://github.com/npm/npm/issues/13306
RUN rm -r node_modules \
&& npm install bower \
&& npm install \
&& mkdir ~/media \
&& sed -i "/^MEDIA_ROOT/c\MEDIA_ROOT='\/home\/wger\/media'" settings.py \
&& . /home/wger/venv/bin/activate \
&& python manage.py download-exercise-images
RUN chown -R wger:wger .
USER wger
RUN mkdir ~/media \
&& mkdir ~/db/
CMD ["/bin/bash"]
CMD ["/home/wger/entrypoint.sh"]

View File

@@ -1,55 +1,82 @@
Development image for wger - Ubuntu based
=========================================
# Development image for wger
Thank you for downloading wger Workout Manager. wger (ˈɡɐ) is a free, open
source web application that manages your exercises and personal workouts, weight
and diet plans. It can also be used as a simple gym management utility, providing
different administrative roles (trainer, manager, etc.). It offers a REST API
as well, for easy integration with other projects and tools.
It is written with python/django and uses jQuery and some D3js for charts.
Installation
------------
## Usage
This docker image contains an instance of the application running with django's
development server using a sqlite database. It can be used to quickly setup a
development instance (vim and tmux are already installed):
This docker image is meant to provide a quick development environment using
django's development server and an sqlite database from your current code
checkout (if you don't want or need a local checkout, use the wger/apache image,
it is self-contained)
```docker run -ti --name wger.devel --publish 8000:8000 wger/devel```
### 1 - Start the container
Then, *within the docker image*, activate the virtualenv
```source ~/venv/bin/activate```
docker run -ti \
-v /path/to/your/wger/checkout:/home/wger/src \
--name wger.devel \
--publish 8000:8000 wger/devel
and start the development server
When developing with windows, you might have problems with the `--volume` option,
use the more verbose mount instead:
```python manage.py runserver 0.0.0.0:8000```
--mount type=bind,source='"C:\your\path\to your\checkout"',target=/home/wger/src
Then just open http://localhost:8000 and log in as: **admin**, password **admin**
You might also want to download the exercise images (will take some time):
Contact
-------
docker exec -ti wger.devel python3 manage.py download-exercise-images
### 2 - Open the Application
Just open <http://localhost:8000> and log in as: **admin**, password **admin**
To stop the container:
```sudo docker container stop wger.devel```
To start developing again:
```sudo docker container start --attach wger.devel```
### 3 - Other commands
If you need to update the CSS/JS libraries or just issue some other command:
docker exec -ti wger.devel yarn
docker exec -ti wger.devel /bin/bash
## Building
If you build this yourself, keep in mind that you **must** build from the
project root!
```docker build -f extras/docker/development/Dockerfile --tag wger/devel .```
## Contact
Feel free to contact us if you found this useful or if there was something that
didn't behave as you expected. We can't fix what we don't know about, so please
report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway.
* twitter: https://twitter.com/wger_de
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger
* issue tracker: https://github.com/wger-project/wger/issues
* gitter: <https://gitter.im/wger-project/wger>
* issue tracker: <https://github.com/wger-project/wger/issues>
* twitter: <https://twitter.com/wger_project>
* mailing list: <https://groups.google.com/group/wger> / wger@googlegroups.com, no registration needed
Sources
-------
## Sources
All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger
* Mirror: https://bitbucket.org/rolandgeider/wger
* Main repository: <https://github.com/wger-project/wger>
Licence
-------
## Licence
The application is licenced under the Affero GNU General Public License 3 or
later (AGPL 3+).

View File

@@ -0,0 +1,31 @@
#!/bin/bash
# Copy a settings file if nothing's found (e.g. when mounting a fresh checkout)
if [ ! -f /home/wger/src/settings.py ]; then
cp /tmp/settings.py /home/wger/src
fi
# If using docker compose, wait for postgres
if [[ "$DJANGO_DB_PORT" == "5432" ]]; then
echo "Waiting for postgres..."
while ! nc -z $DJANGO_DB_HOST $DJANGO_DB_PORT; do
sleep 0.1
done
echo "PostgreSQL started :)"
fi
# Bootstrap the application
wger bootstrap \
--settings-path /home/wger/src/settings.py \
--no-start-server
if [[ "$WGER_DOWNLOAD_IMGS" == "TRUE" ]];
then
wger download-exercise-images
chmod -R g+w ~wger/media
fi
# Run the development server
python3 manage.py runserver 0.0.0.0:8000

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# wger
from wger.settings_global import *
# Use 'DEBUG = True' to get more details for server errors
DEBUG = True
TEMPLATES[0]['OPTIONS']['debug'] = True
ADMINS = (
('Your name', 'your_email@example.com'),
)
MANAGERS = ADMINS
if os.environ.get("DJANGO_DB_ENGINE"):
DATABASES = {
'default': {
'ENGINE': os.environ.get("DJANGO_DB_ENGINE"),
'NAME': os.environ.get("DJANGO_DB_DATABASE"),
'USER': os.environ.get("DJANGO_DB_USER"),
'PASSWORD': os.environ.get("DJANGO_DB_PASSWORD"),
'HOST': os.environ.get("DJANGO_DB_HOST"),
'PORT': os.environ.get("DJANGO_DB_PART"),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/home/wger/db/database.sqlite',
}
}
# Timezone for this installation. Consult settings_global.py for more information
TIME_ZONE = 'Europe/Berlin'
# Make this unique, and don't share it with anybody.
SECRET_KEY = '3^st!i-*a*iy!-4-^!rc8nv)-q34dg3u6f=bl%!h+!$xbznqj5'
# Your reCaptcha keys
RECAPTCHA_PUBLIC_KEY = ''
RECAPTCHA_PRIVATE_KEY = ''
NOCAPTCHA = True
# The site's URL (e.g. http://www.my-local-gym.com or http://localhost:8000)
# This is needed for uploaded files and images (exercise images, etc.) to be
# properly served.
SITE_URL = 'http://localhost:8000'
# Path to uploaded files
# Absolute filesystem path to the directory that will hold user-uploaded files.
MEDIA_ROOT = '/home/wger/media'
MEDIA_URL = '/media/'
# Allow all hosts to access the application. Change if used in production.
ALLOWED_HOSTS = '*'
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# Configure a real backend in production
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Sender address used for sent emails
WGER_SETTINGS['EMAIL_FROM'] = 'wger Workout Manager <wger@example.com>'
if os.environ.get("DJANGO_CACHE_BACKEND"):
CACHES = {
'default': {
'BACKEND': os.environ.get("DJANGO_CACHE_BACKEND"),
'LOCATION': os.environ.get("DJANGO_CACHE_LOCATION"),
'TIMEOUT': os.environ.get("DJANGO_CACHE_TIMEOUT"),
'OPTIONS': {
'CLIENT_CLASS': os.environ.get("DJANGO_CACHE_CLIENT_CLASS"),
}
}
}

View File

@@ -0,0 +1 @@
https://www.ssa.gov/oact/babynames/decades/names2010s.html

View File

@@ -0,0 +1,400 @@
"Jacob","m"
"Noah","m"
"Mason","m"
"William","m"
"Ethan","m"
"Liam","m"
"Michael","m"
"Alexander","m"
"Jayden","m"
"Daniel","m"
"Aiden","m"
"James","m"
"Elijah","m"
"Matthew","m"
"Benjamin","m"
"Logan","m"
"Anthony","m"
"David","m"
"Joseph","m"
"Joshua","m"
"Jackson","m"
"Andrew","m"
"Christopher","m"
"Gabriel","m"
"Samuel","m"
"Lucas","m"
"John","m"
"Ryan","m"
"Dylan","m"
"Nathan","m"
"Isaac","m"
"Caleb","m"
"Carter","m"
"Christian","m"
"Luke","m"
"Jonathan","m"
"Landon","m"
"Owen","m"
"Jack","m"
"Wyatt","m"
"Henry","m"
"Hunter","m"
"Isaiah","m"
"Brayden","m"
"Gavin","m"
"Nicholas","m"
"Sebastian","m"
"Evan","m"
"Julian","m"
"Tyler","m"
"Aaron","m"
"Jordan","m"
"Eli","m"
"Oliver","m"
"Levi","m"
"Connor","m"
"Jeremiah","m"
"Cameron","m"
"Charles","m"
"Angel","m"
"Thomas","m"
"Adrian","m"
"Robert","m"
"Brandon","m"
"Austin","m"
"Jaxon","m"
"Kevin","m"
"Jose","m"
"Colton","m"
"Zachary","m"
"Josiah","m"
"Dominic","m"
"Chase","m"
"Ayden","m"
"Jason","m"
"Justin","m"
"Ian","m"
"Parker","m"
"Grayson","m"
"Adam","m"
"Blake","m"
"Xavier","m"
"Cooper","m"
"Bentley","m"
"Jace","m"
"Carson","m"
"Nolan","m"
"Nathaniel","m"
"Brody","m"
"Hudson","m"
"Tristan","m"
"Luis","m"
"Juan","m"
"Easton","m"
"Kayden","m"
"Carlos","m"
"Jaxson","m"
"Asher","m"
"Cole","m"
"Jesus","m"
"Ryder","m"
"Vincent","m"
"Alex","m"
"Micah","m"
"Max","m"
"Lincoln","m"
"Bryson","m"
"Damian","m"
"Diego","m"
"Eric","m"
"Hayden","m"
"Elias","m"
"Miles","m"
"Maxwell","m"
"Bryce","m"
"Giovanni","m"
"Leo","m"
"Mateo","m"
"Santiago","m"
"Camden","m"
"Bryan","m"
"Timothy","m"
"Antonio","m"
"Aidan","m"
"Jaden","m"
"Steven","m"
"Sawyer","m"
"Colin","m"
"Leonardo","m"
"Ivan","m"
"Ashton","m"
"Kaleb","m"
"Miguel","m"
"Richard","m"
"Braxton","m"
"Jonah","m"
"Kaden","m"
"Roman","m"
"Brian","m"
"Kyle","m"
"Riley","m"
"Alejandro","m"
"Victor","m"
"Preston","m"
"Joel","m"
"Kaiden","m"
"Wesley","m"
"Patrick","m"
"Jesse","m"
"Marcus","m"
"Declan","m"
"Edward","m"
"Axel","m"
"Sean","m"
"Ezra","m"
"Jake","m"
"Silas","m"
"George","m"
"Jeremy","m"
"Brady","m"
"Caden","m"
"Emmanuel","m"
"Jude","m"
"Grant","m"
"Alan","m"
"Greyson","m"
"Theodore","m"
"Harrison","m"
"Maddox","m"
"Weston","m"
"Malachi","m"
"Oscar","m"
"Cayden","m"
"Brantley","m"
"Bradley","m"
"Mark","m"
"Kenneth","m"
"Jayce","m"
"Nicolas","m"
"Emmett","m"
"Gage","m"
"Abraham","m"
"Ezekiel","m"
"Kai","m"
"Kingston","m"
"Abel","m"
"Jase","m"
"Tucker","m"
"Jameson","m"
"Devin","m"
"Paul","m"
"Derek","m"
"Rylan","m"
"Calvin","m"
"Peyton","m"
"Tanner","m"
"Avery","m"
"Everett","m"
"Bennett","m"
"Ryker","m"
"Sophia","f"
"Emma","f"
"Isabella","f"
"Olivia","f"
"Ava","f"
"Emily","f"
"Abigail","f"
"Mia","f"
"Madison","f"
"Elizabeth","f"
"Chloe","f"
"Ella","f"
"Avery","f"
"Charlotte","f"
"Sofia","f"
"Addison","f"
"Natalie","f"
"Amelia","f"
"Grace","f"
"Evelyn","f"
"Lily","f"
"Aubrey","f"
"Victoria","f"
"Harper","f"
"Lillian","f"
"Hannah","f"
"Zoey","f"
"Samantha","f"
"Brooklyn","f"
"Layla","f"
"Zoe","f"
"Leah","f"
"Anna","f"
"Hailey","f"
"Allison","f"
"Gabriella","f"
"Alexis","f"
"Audrey","f"
"Savannah","f"
"Kaylee","f"
"Sarah","f"
"Riley","f"
"Nevaeh","f"
"Aaliyah","f"
"Camila","f"
"Alyssa","f"
"Claire","f"
"Arianna","f"
"Scarlett","f"
"Alexa","f"
"Taylor","f"
"Ashley","f"
"Brianna","f"
"Peyton","f"
"Bella","f"
"Ariana","f"
"Kylie","f"
"Khloe","f"
"Serenity","f"
"Stella","f"
"Lucy","f"
"Maya","f"
"Sophie","f"
"Madelyn","f"
"Genesis","f"
"Julia","f"
"Aria","f"
"Mackenzie","f"
"Autumn","f"
"Katherine","f"
"Caroline","f"
"Ellie","f"
"Kennedy","f"
"Kayla","f"
"Sadie","f"
"Makayla","f"
"Violet","f"
"Lauren","f"
"Faith","f"
"Gianna","f"
"Penelope","f"
"Skylar","f"
"Eva","f"
"Alexandra","f"
"Melanie","f"
"Aubree","f"
"Nora","f"
"Naomi","f"
"Sydney","f"
"Madeline","f"
"Jasmine","f"
"Morgan","f"
"Kimberly","f"
"Annabelle","f"
"Lydia","f"
"Jocelyn","f"
"Piper","f"
"Bailey","f"
"Paisley","f"
"London","f"
"Trinity","f"
"Ruby","f"
"Andrea","f"
"Molly","f"
"Maria","f"
"Mila","f"
"Eleanor","f"
"Brooke","f"
"Reagan","f"
"Isabelle","f"
"Rylee","f"
"Payton","f"
"Natalia","f"
"Mariah","f"
"Mary","f"
"Paige","f"
"Lilly","f"
"Alice","f"
"Nicole","f"
"Destiny","f"
"Mya","f"
"Jade","f"
"Liliana","f"
"Jordyn","f"
"Vivian","f"
"Kaitlyn","f"
"Brielle","f"
"Kendall","f"
"Clara","f"
"Angelina","f"
"Hadley","f"
"Eliana","f"
"Rachel","f"
"Isabel","f"
"Valentina","f"
"Elena","f"
"Gabrielle","f"
"Vanessa","f"
"Cora","f"
"Hazel","f"
"Katelyn","f"
"Lyla","f"
"Aurora","f"
"Valeria","f"
"Jessica","f"
"Quinn","f"
"Sara","f"
"Amy","f"
"Delilah","f"
"Mckenzie","f"
"Brooklynn","f"
"Reese","f"
"Laila","f"
"Aliyah","f"
"Adriana","f"
"Gracie","f"
"Juliana","f"
"Josephine","f"
"Michelle","f"
"Willow","f"
"Rebecca","f"
"Eden","f"
"Makenzie","f"
"Ariel","f"
"Valerie","f"
"Elise","f"
"Kinsley","f"
"Stephanie","f"
"Kylee","f"
"Jennifer","f"
"Izabella","f"
"Jayla","f"
"Catherine","f"
"Ximena","f"
"Melody","f"
"Margaret","f"
"Ivy","f"
"Daisy","f"
"Alaina","f"
"Lila","f"
"Adalyn","f"
"Summer","f"
"Giselle","f"
"Luna","f"
"Julianna","f"
"Alana","f"
"Londyn","f"
"Hayden","f"
"Ryleigh","f"
"Daniela","f"
"Angela","f"
"Isla","f"
"Alivia","f"
"Adalynn","f"
"Emery","f"
"Melissa","f"
"Kate","f"
"Gabriela","f"
"Keira","f"
"Norah","f"
1 Jacob m
2 Noah m
3 Mason m
4 William m
5 Ethan m
6 Liam m
7 Michael m
8 Alexander m
9 Jayden m
10 Daniel m
11 Aiden m
12 James m
13 Elijah m
14 Matthew m
15 Benjamin m
16 Logan m
17 Anthony m
18 David m
19 Joseph m
20 Joshua m
21 Jackson m
22 Andrew m
23 Christopher m
24 Gabriel m
25 Samuel m
26 Lucas m
27 John m
28 Ryan m
29 Dylan m
30 Nathan m
31 Isaac m
32 Caleb m
33 Carter m
34 Christian m
35 Luke m
36 Jonathan m
37 Landon m
38 Owen m
39 Jack m
40 Wyatt m
41 Henry m
42 Hunter m
43 Isaiah m
44 Brayden m
45 Gavin m
46 Nicholas m
47 Sebastian m
48 Evan m
49 Julian m
50 Tyler m
51 Aaron m
52 Jordan m
53 Eli m
54 Oliver m
55 Levi m
56 Connor m
57 Jeremiah m
58 Cameron m
59 Charles m
60 Angel m
61 Thomas m
62 Adrian m
63 Robert m
64 Brandon m
65 Austin m
66 Jaxon m
67 Kevin m
68 Jose m
69 Colton m
70 Zachary m
71 Josiah m
72 Dominic m
73 Chase m
74 Ayden m
75 Jason m
76 Justin m
77 Ian m
78 Parker m
79 Grayson m
80 Adam m
81 Blake m
82 Xavier m
83 Cooper m
84 Bentley m
85 Jace m
86 Carson m
87 Nolan m
88 Nathaniel m
89 Brody m
90 Hudson m
91 Tristan m
92 Luis m
93 Juan m
94 Easton m
95 Kayden m
96 Carlos m
97 Jaxson m
98 Asher m
99 Cole m
100 Jesus m
101 Ryder m
102 Vincent m
103 Alex m
104 Micah m
105 Max m
106 Lincoln m
107 Bryson m
108 Damian m
109 Diego m
110 Eric m
111 Hayden m
112 Elias m
113 Miles m
114 Maxwell m
115 Bryce m
116 Giovanni m
117 Leo m
118 Mateo m
119 Santiago m
120 Camden m
121 Bryan m
122 Timothy m
123 Antonio m
124 Aidan m
125 Jaden m
126 Steven m
127 Sawyer m
128 Colin m
129 Leonardo m
130 Ivan m
131 Ashton m
132 Kaleb m
133 Miguel m
134 Richard m
135 Braxton m
136 Jonah m
137 Kaden m
138 Roman m
139 Brian m
140 Kyle m
141 Riley m
142 Alejandro m
143 Victor m
144 Preston m
145 Joel m
146 Kaiden m
147 Wesley m
148 Patrick m
149 Jesse m
150 Marcus m
151 Declan m
152 Edward m
153 Axel m
154 Sean m
155 Ezra m
156 Jake m
157 Silas m
158 George m
159 Jeremy m
160 Brady m
161 Caden m
162 Emmanuel m
163 Jude m
164 Grant m
165 Alan m
166 Greyson m
167 Theodore m
168 Harrison m
169 Maddox m
170 Weston m
171 Malachi m
172 Oscar m
173 Cayden m
174 Brantley m
175 Bradley m
176 Mark m
177 Kenneth m
178 Jayce m
179 Nicolas m
180 Emmett m
181 Gage m
182 Abraham m
183 Ezekiel m
184 Kai m
185 Kingston m
186 Abel m
187 Jase m
188 Tucker m
189 Jameson m
190 Devin m
191 Paul m
192 Derek m
193 Rylan m
194 Calvin m
195 Peyton m
196 Tanner m
197 Avery m
198 Everett m
199 Bennett m
200 Ryker m
201 Sophia f
202 Emma f
203 Isabella f
204 Olivia f
205 Ava f
206 Emily f
207 Abigail f
208 Mia f
209 Madison f
210 Elizabeth f
211 Chloe f
212 Ella f
213 Avery f
214 Charlotte f
215 Sofia f
216 Addison f
217 Natalie f
218 Amelia f
219 Grace f
220 Evelyn f
221 Lily f
222 Aubrey f
223 Victoria f
224 Harper f
225 Lillian f
226 Hannah f
227 Zoey f
228 Samantha f
229 Brooklyn f
230 Layla f
231 Zoe f
232 Leah f
233 Anna f
234 Hailey f
235 Allison f
236 Gabriella f
237 Alexis f
238 Audrey f
239 Savannah f
240 Kaylee f
241 Sarah f
242 Riley f
243 Nevaeh f
244 Aaliyah f
245 Camila f
246 Alyssa f
247 Claire f
248 Arianna f
249 Scarlett f
250 Alexa f
251 Taylor f
252 Ashley f
253 Brianna f
254 Peyton f
255 Bella f
256 Ariana f
257 Kylie f
258 Khloe f
259 Serenity f
260 Stella f
261 Lucy f
262 Maya f
263 Sophie f
264 Madelyn f
265 Genesis f
266 Julia f
267 Aria f
268 Mackenzie f
269 Autumn f
270 Katherine f
271 Caroline f
272 Ellie f
273 Kennedy f
274 Kayla f
275 Sadie f
276 Makayla f
277 Violet f
278 Lauren f
279 Faith f
280 Gianna f
281 Penelope f
282 Skylar f
283 Eva f
284 Alexandra f
285 Melanie f
286 Aubree f
287 Nora f
288 Naomi f
289 Sydney f
290 Madeline f
291 Jasmine f
292 Morgan f
293 Kimberly f
294 Annabelle f
295 Lydia f
296 Jocelyn f
297 Piper f
298 Bailey f
299 Paisley f
300 London f
301 Trinity f
302 Ruby f
303 Andrea f
304 Molly f
305 Maria f
306 Mila f
307 Eleanor f
308 Brooke f
309 Reagan f
310 Isabelle f
311 Rylee f
312 Payton f
313 Natalia f
314 Mariah f
315 Mary f
316 Paige f
317 Lilly f
318 Alice f
319 Nicole f
320 Destiny f
321 Mya f
322 Jade f
323 Liliana f
324 Jordyn f
325 Vivian f
326 Kaitlyn f
327 Brielle f
328 Kendall f
329 Clara f
330 Angelina f
331 Hadley f
332 Eliana f
333 Rachel f
334 Isabel f
335 Valentina f
336 Elena f
337 Gabrielle f
338 Vanessa f
339 Cora f
340 Hazel f
341 Katelyn f
342 Lyla f
343 Aurora f
344 Valeria f
345 Jessica f
346 Quinn f
347 Sara f
348 Amy f
349 Delilah f
350 Mckenzie f
351 Brooklynn f
352 Reese f
353 Laila f
354 Aliyah f
355 Adriana f
356 Gracie f
357 Juliana f
358 Josephine f
359 Michelle f
360 Willow f
361 Rebecca f
362 Eden f
363 Makenzie f
364 Ariel f
365 Valerie f
366 Elise f
367 Kinsley f
368 Stephanie f
369 Kylee f
370 Jennifer f
371 Izabella f
372 Jayla f
373 Catherine f
374 Ximena f
375 Melody f
376 Margaret f
377 Ivy f
378 Daisy f
379 Alaina f
380 Lila f
381 Adalyn f
382 Summer f
383 Giselle f
384 Luna f
385 Julianna f
386 Alana f
387 Londyn f
388 Hayden f
389 Ryleigh f
390 Daniela f
391 Angela f
392 Isla f
393 Alivia f
394 Adalynn f
395 Emery f
396 Melissa f
397 Kate f
398 Gabriela f
399 Keira f
400 Norah f

View File

@@ -0,0 +1 @@
https://www.census.gov/topics/population/genealogy/data/2010_surnames.html

View File

@@ -0,0 +1,500 @@
Smith
Johnson
Williams
Brown
Jones
Garcia
Miller
Davis
Rodriguez
Martinez
Hernandez
Lopez
Gonzalez
Wilson
Anderson
Thomas
Taylor
Moore
Jackson
Martin
Lee
Perez
Thompson
White
Harris
Sanchez
Clark
Ramirez
Lewis
Robinson
Walker
Young
Allen
King
Wright
Scott
Torres
Nguyen
Hill
Flores
Green
Adams
Nelson
Baker
Hall
Rivera
Campbell
Mitchell
Carter
Roberts
Gomez
Phillips
Evans
Turner
Diaz
Parker
Cruz
Edwards
Collins
Reyes
Stewart
Morris
Morales
Murphy
Cook
Rogers
Gutierrez
Ortiz
Morgan
Cooper
Peterson
Bailey
Reed
Kelly
Howard
Ramos
Kim
Cox
Ward
Richardson
Watson
Brooks
Chavez
Wood
James
Bennett
Gray
Mendoza
Ruiz
Hughes
Price
Alvarez
Castillo
Sanders
Patel
Myers
Long
Ross
Foster
Jimenez
Powell
Jenkins
Perry
Russell
Sullivan
Bell
Coleman
Butler
Henderson
Barnes
Gonzales
Fisher
Vasquez
Simmons
Romero
Jordan
Patterson
Alexander
Hamilton
Graham
Reynolds
Griffin
Wallace
Moreno
West
Cole
Hayes
Bryant
Herrera
Gibson
Ellis
Tran
Medina
Aguilar
Stevens
Murray
Ford
Castro
Marshall
Owens
Harrison
Fernandez
Mcdonald
Woods
Washington
Kennedy
Wells
Vargas
Henry
Chen
Freeman
Webb
Tucker
Guzman
Burns
Crawford
Olson
Simpson
Porter
Hunter
Gordon
Mendez
Silva
Shaw
Snyder
Mason
Dixon
Munoz
Hunt
Hicks
Holmes
Palmer
Wagner
Black
Robertson
Boyd
Rose
Stone
Salazar
Fox
Warren
Mills
Meyer
Rice
Schmidt
Garza
Daniels
Ferguson
Nichols
Stephens
Soto
Weaver
Ryan
Gardner
Payne
Grant
Dunn
Kelley
Spencer
Hawkins
Arnold
Pierce
Vazquez
Hansen
Peters
Santos
Hart
Bradley
Knight
Elliott
Cunningham
Duncan
Armstrong
Hudson
Carroll
Lane
Riley
Andrews
Alvarado
Ray
Delgado
Berry
Perkins
Hoffman
Johnston
Matthews
Pena
Richards
Contreras
Willis
Carpenter
Lawrence
Sandoval
Guerrero
George
Chapman
Rios
Estrada
Ortega
Watkins
Greene
Nunez
Wheeler
Valdez
Harper
Burke
Larson
Santiago
Maldonado
Morrison
Franklin
Carlson
Austin
Dominguez
Carr
Lawson
Jacobs
Obrien
Lynch
Singh
Vega
Bishop
Montgomery
Oliver
Jensen
Harvey
Williamson
Gilbert
Dean
Sims
Espinoza
Howell
Li
Wong
Reid
Hanson
Le
Mccoy
Garrett
Burton
Fuller
Wang
Weber
Welch
Rojas
Lucas
Marquez
Fields
Park
Yang
Little
Banks
Padilla
Day
Walsh
Bowman
Schultz
Luna
Fowler
Mejia
Davidson
Acosta
Brewer
May
Holland
Juarez
Newman
Pearson
Curtis
Cortez
Douglas
Schneider
Joseph
Barrett
Navarro
Figueroa
Keller
Avila
Wade
Molina
Stanley
Hopkins
Campos
Barnett
Bates
Chambers
Caldwell
Beck
Lambert
Miranda
Byrd
Craig
Ayala
Lowe
Frazier
Powers
Neal
Leonard
Gregory
Carrillo
Sutton
Fleming
Rhodes
Shelton
Schwartz
Norris
Jennings
Watts
Duran
Walters
Cohen
Mcdaniel
Moran
Parks
Steele
Vaughn
Becker
Holt
Deleon
Barker
Terry
Hale
Leon
Hail
Benson
Haynes
Horton
Miles
Lyons
Pham
Graves
Bush
Thornton
Wolfe
Warner
Cabrera
Mckinney
Mann
Zimmerman
Dawson
Lara
Fletcher
Page
Mccarthy
Love
Robles
Cervantes
Solis
Erickson
Reeves
Chang
Klein
Salinas
Fuentes
Baldwin
Daniel
Simon
Velasquez
Hardy
Higgins
Aguirre
Lin
Cummings
Chandler
Sharp
Barber
Bowen
Ochoa
Dennis
Robbins
Liu
Ramsey
Francis
Griffith
Paul
Blair
Oconnor
Cardenas
Pacheco
Cross
Calderon
Quinn
Moss
Swanson
Chan
Rivas
Khan
Rodgers
Serrano
Fitzgerald
Rosales
Stevenson
Christensen
Manning
Gill
Curry
Mclaughlin
Harmon
Mcgee
Gross
Doyle
Garner
Newton
Burgess
Reese
Walton
Blake
Trujillo
Adkins
Brady
Goodman
Roman
Webster
Goodwin
Fischer
Huang
Potter
Delacruz
Montoya
Todd
Wu
Hines
Mullins
Castaneda
Malone
Cannon
Tate
Mack
Sherman
Hubbard
Hodges
Zhang
Guerra
Wolf
Valencia
Saunders
Franco
Rowe
Gallagher
Farmer
Hammond
Hampton
Townsend
Ingram
Wise
Gallegos
Clarke
Barton
Schroeder
Maxwell
Waters
Logan
Camacho
Strickland
Norman
Person
Colon
Parsons
Frank
Harrington
1 Smith
2 Johnson
3 Williams
4 Brown
5 Jones
6 Garcia
7 Miller
8 Davis
9 Rodriguez
10 Martinez
11 Hernandez
12 Lopez
13 Gonzalez
14 Wilson
15 Anderson
16 Thomas
17 Taylor
18 Moore
19 Jackson
20 Martin
21 Lee
22 Perez
23 Thompson
24 White
25 Harris
26 Sanchez
27 Clark
28 Ramirez
29 Lewis
30 Robinson
31 Walker
32 Young
33 Allen
34 King
35 Wright
36 Scott
37 Torres
38 Nguyen
39 Hill
40 Flores
41 Green
42 Adams
43 Nelson
44 Baker
45 Hall
46 Rivera
47 Campbell
48 Mitchell
49 Carter
50 Roberts
51 Gomez
52 Phillips
53 Evans
54 Turner
55 Diaz
56 Parker
57 Cruz
58 Edwards
59 Collins
60 Reyes
61 Stewart
62 Morris
63 Morales
64 Murphy
65 Cook
66 Rogers
67 Gutierrez
68 Ortiz
69 Morgan
70 Cooper
71 Peterson
72 Bailey
73 Reed
74 Kelly
75 Howard
76 Ramos
77 Kim
78 Cox
79 Ward
80 Richardson
81 Watson
82 Brooks
83 Chavez
84 Wood
85 James
86 Bennett
87 Gray
88 Mendoza
89 Ruiz
90 Hughes
91 Price
92 Alvarez
93 Castillo
94 Sanders
95 Patel
96 Myers
97 Long
98 Ross
99 Foster
100 Jimenez
101 Powell
102 Jenkins
103 Perry
104 Russell
105 Sullivan
106 Bell
107 Coleman
108 Butler
109 Henderson
110 Barnes
111 Gonzales
112 Fisher
113 Vasquez
114 Simmons
115 Romero
116 Jordan
117 Patterson
118 Alexander
119 Hamilton
120 Graham
121 Reynolds
122 Griffin
123 Wallace
124 Moreno
125 West
126 Cole
127 Hayes
128 Bryant
129 Herrera
130 Gibson
131 Ellis
132 Tran
133 Medina
134 Aguilar
135 Stevens
136 Murray
137 Ford
138 Castro
139 Marshall
140 Owens
141 Harrison
142 Fernandez
143 Mcdonald
144 Woods
145 Washington
146 Kennedy
147 Wells
148 Vargas
149 Henry
150 Chen
151 Freeman
152 Webb
153 Tucker
154 Guzman
155 Burns
156 Crawford
157 Olson
158 Simpson
159 Porter
160 Hunter
161 Gordon
162 Mendez
163 Silva
164 Shaw
165 Snyder
166 Mason
167 Dixon
168 Munoz
169 Hunt
170 Hicks
171 Holmes
172 Palmer
173 Wagner
174 Black
175 Robertson
176 Boyd
177 Rose
178 Stone
179 Salazar
180 Fox
181 Warren
182 Mills
183 Meyer
184 Rice
185 Schmidt
186 Garza
187 Daniels
188 Ferguson
189 Nichols
190 Stephens
191 Soto
192 Weaver
193 Ryan
194 Gardner
195 Payne
196 Grant
197 Dunn
198 Kelley
199 Spencer
200 Hawkins
201 Arnold
202 Pierce
203 Vazquez
204 Hansen
205 Peters
206 Santos
207 Hart
208 Bradley
209 Knight
210 Elliott
211 Cunningham
212 Duncan
213 Armstrong
214 Hudson
215 Carroll
216 Lane
217 Riley
218 Andrews
219 Alvarado
220 Ray
221 Delgado
222 Berry
223 Perkins
224 Hoffman
225 Johnston
226 Matthews
227 Pena
228 Richards
229 Contreras
230 Willis
231 Carpenter
232 Lawrence
233 Sandoval
234 Guerrero
235 George
236 Chapman
237 Rios
238 Estrada
239 Ortega
240 Watkins
241 Greene
242 Nunez
243 Wheeler
244 Valdez
245 Harper
246 Burke
247 Larson
248 Santiago
249 Maldonado
250 Morrison
251 Franklin
252 Carlson
253 Austin
254 Dominguez
255 Carr
256 Lawson
257 Jacobs
258 Obrien
259 Lynch
260 Singh
261 Vega
262 Bishop
263 Montgomery
264 Oliver
265 Jensen
266 Harvey
267 Williamson
268 Gilbert
269 Dean
270 Sims
271 Espinoza
272 Howell
273 Li
274 Wong
275 Reid
276 Hanson
277 Le
278 Mccoy
279 Garrett
280 Burton
281 Fuller
282 Wang
283 Weber
284 Welch
285 Rojas
286 Lucas
287 Marquez
288 Fields
289 Park
290 Yang
291 Little
292 Banks
293 Padilla
294 Day
295 Walsh
296 Bowman
297 Schultz
298 Luna
299 Fowler
300 Mejia
301 Davidson
302 Acosta
303 Brewer
304 May
305 Holland
306 Juarez
307 Newman
308 Pearson
309 Curtis
310 Cortez
311 Douglas
312 Schneider
313 Joseph
314 Barrett
315 Navarro
316 Figueroa
317 Keller
318 Avila
319 Wade
320 Molina
321 Stanley
322 Hopkins
323 Campos
324 Barnett
325 Bates
326 Chambers
327 Caldwell
328 Beck
329 Lambert
330 Miranda
331 Byrd
332 Craig
333 Ayala
334 Lowe
335 Frazier
336 Powers
337 Neal
338 Leonard
339 Gregory
340 Carrillo
341 Sutton
342 Fleming
343 Rhodes
344 Shelton
345 Schwartz
346 Norris
347 Jennings
348 Watts
349 Duran
350 Walters
351 Cohen
352 Mcdaniel
353 Moran
354 Parks
355 Steele
356 Vaughn
357 Becker
358 Holt
359 Deleon
360 Barker
361 Terry
362 Hale
363 Leon
364 Hail
365 Benson
366 Haynes
367 Horton
368 Miles
369 Lyons
370 Pham
371 Graves
372 Bush
373 Thornton
374 Wolfe
375 Warner
376 Cabrera
377 Mckinney
378 Mann
379 Zimmerman
380 Dawson
381 Lara
382 Fletcher
383 Page
384 Mccarthy
385 Love
386 Robles
387 Cervantes
388 Solis
389 Erickson
390 Reeves
391 Chang
392 Klein
393 Salinas
394 Fuentes
395 Baldwin
396 Daniel
397 Simon
398 Velasquez
399 Hardy
400 Higgins
401 Aguirre
402 Lin
403 Cummings
404 Chandler
405 Sharp
406 Barber
407 Bowen
408 Ochoa
409 Dennis
410 Robbins
411 Liu
412 Ramsey
413 Francis
414 Griffith
415 Paul
416 Blair
417 Oconnor
418 Cardenas
419 Pacheco
420 Cross
421 Calderon
422 Quinn
423 Moss
424 Swanson
425 Chan
426 Rivas
427 Khan
428 Rodgers
429 Serrano
430 Fitzgerald
431 Rosales
432 Stevenson
433 Christensen
434 Manning
435 Gill
436 Curry
437 Mclaughlin
438 Harmon
439 Mcgee
440 Gross
441 Doyle
442 Garner
443 Newton
444 Burgess
445 Reese
446 Walton
447 Blake
448 Trujillo
449 Adkins
450 Brady
451 Goodman
452 Roman
453 Webster
454 Goodwin
455 Fischer
456 Huang
457 Potter
458 Delacruz
459 Montoya
460 Todd
461 Wu
462 Hines
463 Mullins
464 Castaneda
465 Malone
466 Cannon
467 Tate
468 Mack
469 Sherman
470 Hubbard
471 Hodges
472 Zhang
473 Guerra
474 Wolf
475 Valencia
476 Saunders
477 Franco
478 Rowe
479 Gallagher
480 Farmer
481 Hammond
482 Hampton
483 Townsend
484 Ingram
485 Wise
486 Gallegos
487 Clarke
488 Barton
489 Schroeder
490 Maxwell
491 Waters
492 Logan
493 Camacho
494 Strickland
495 Norman
496 Person
497 Colon
498 Parsons
499 Frank
500 Harrington

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# flake8: noqa
# This file is part of wger Workout Manager.
#
@@ -80,7 +81,7 @@ user_parser.add_argument('--country',
action='store',
default='germany',
help='What country the generated users should belong to. Default: Germany',
choices=['germany', 'ukraine', 'spain'])
choices=['germany', 'ukraine', 'spain', 'usa'])
# Workout options
workouts_parser = subparsers.add_parser('workouts', help='Create workouts')
@@ -452,7 +453,7 @@ if hasattr(args, 'number_nutrition_plans'):
# Total meals per plan
total_meals = 4
for user in userlist:
print(' - generating for {0}'.format(user.username))

View File

@@ -14,24 +14,26 @@
#
# You should have received a copy of the GNU Affero General Public License
'''
"""
Simple script that filters the output of django's dumpdata command into more
manageable chunks.
Create the data.json e.g. with:
python ../../manage.py dumpdata --indent 4 --natural-foreign > data.json
'''
"""
import json
def filter_dump(data, model_list, filename):
'''
"""
Helper function
'''
"""
filter_data = [i for i in data if i['model'] in model_list]
with open(filename, 'w') as outfile:
json.dump(filter_data, outfile, indent=4)
if filter_data:
with open(filename, 'w') as outfile:
json.dump(filter_data, outfile, indent=4)
# This is a full dump of the DB
fixture = open('data.json')
@@ -44,6 +46,7 @@ fixture.close()
filter_dump(data, ('nutrition.ingredient',), 'ingredients.json')
filter_dump(data, ('nutrition.weightunit',), 'weight_units.json')
filter_dump(data, ('nutrition.ingredientweightunit',), 'ingredient_units.json')
filter_dump(data, ('nutrition.logitem',), 'nutrition_diary.json')
#
# Exercises

View File

@@ -1,25 +0,0 @@
const gulp = require('gulp');
const eslint = require('gulp-eslint');
gulp.task('lint-js', function () {
// ESLint ignores files with "node_modules" paths.
// So, it's best to have gulp ignore the directory as well.
// Also, Be sure to return the stream from the task;
// Otherwise, the task may end before the stream has finished.
return gulp.src(['**/*.js'])
// eslint() attaches the lint output to the "eslint" property
// of the file object so it can be used by other modules.
.pipe(eslint())
// eslint.format() outputs the lint results to the console.
// Alternatively use eslint.formatEach() (see Docs).
.pipe(eslint.format())
// To have the process exit with an error code (1) on
// lint error, return the stream and pipe to failAfterError last.
.pipe(eslint.failAfterError());
});
gulp.task('lint', ['lint-js']);
gulp.task('default', ['lint'], function () {
// This will only run if the lint task is successful...
});

View File

@@ -1,13 +1,18 @@
#!/usr/bin/env python
# Standard Library
import sys
# Django
from django.core.management import execute_from_command_line
from tasks import (
setup_django_environment,
get_user_config_path
# wger
from wger.tasks import (
get_user_config_path,
setup_django_environment
)
if __name__ == "__main__":
# If user passed the settings flag ignore the default wger settings

View File

@@ -1,13 +1,10 @@
{
"name": "wger",
"version": "1.8.0",
"version": "2.0.dev1",
"description": "Self hosted FLOSS fitness/workout and weight tracker",
"directories": {
"doc": "docs"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/wger-project/wger/wger.git"
@@ -18,13 +15,20 @@
"url": "https://github.com/wger-project/wger/issues"
},
"homepage": "https://github.com/wger-project/wger",
"devDependencies": {
"eslint": "^3.3.1",
"eslint-config-airbnb-base": "^5.0.2",
"eslint-plugin-import": "^1.13.0",
"eslint-plugin-jsx-a11y": "^2.1.0",
"eslint-plugin-react": "^6.1.2",
"gulp": "^3.9.1",
"gulp-eslint": "^3.0.1"
"dependencies": {
"yarn": "^1.22.5",
"Sortable": "RubaXa/Sortable#1.10.2",
"bootstrap": "twbs/bootstrap#4.x",
"components-font-awesome": "components/font-awesome#5.14.0",
"d3": "mbostock-bower/d3-bower#>=5",
"datatables": "DataTables/DataTables#1.10.x",
"devbridge-autocomplete": "^1.4.11",
"jquery": "^3.5.0",
"metrics-graphics": "mozilla/metrics-graphics#2.15.x",
"shariff": "^3.2.1",
"tinymce": "^5.4.2"
},
"engines": {
"yarn": ">= 1.0.0"
}
}

View File

@@ -2,30 +2,49 @@
# Requirements for wger for production
#
bleach
# Building/installing
wheel
# Application
bleach~=3.1
django-activity-stream
django-bootstrap-breadcrumbs
django-bower
django-formtools>=1.0,<1.1
django-recaptcha
django-sortedm2m
Django>=1.9,<1.10
django_compressor
django_mobile
easy-thumbnails
icalendar
invoke>=0.14,<0.15
pillow
django-bootstrap-breadcrumbs~=0.9
django-formtools~=2.2
django-recaptcha==2.0.6
Django~=3.1
django-crispy-forms~=1.9
django_compressor~=2.4
django_extensions~=3.0
django-sortedm2m~=3.0
django-storages~=1.9
easy-thumbnails~=2.7
icalendar==4.0.6
invoke~=1.4
pillow~=7.2
python-mimeparse
reportlab>=3.3,<3.4
reportlab==3.5.48
matplotlib>=3.1
requests
setuptools>=18.5
sphinx
# REST API
django-cors-headers
django-filter
django-tastypie>=0.13,<0.14
djangorestframework>=3.2,<3.3
# AWS
#boto3
# Production
#psycopg2
#python-memcached
# REST API
django-cors-headers>=3.0
django-filter==2.3.0
djangorestframework~=3.11
# Explicitly set versions as a workaround for CI/Devel.
# This is just intended to make life easier, has no deeper meaning and
# can be removed if needed.
docutils>=0.10,<0.17 # for botocore
six>=1.12.0 # for django-compressor
# Python3 compatibility
six

View File

@@ -6,6 +6,8 @@
-r requirements.txt
# Development packages
pep8
coverage
django-debug-toolbar
coverage
tblib
transifex-client
isort

View File

@@ -1,7 +1,69 @@
[bdist_wheel]
universal = 1
[pep8]
exclude = urls.py,tasks.py,*migrations*,*bower_components*
max-line-length = 100
ignore = W503
[isort]
sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
skip: extras,build,dist,node_modules,migrations,docs,settings.py,apps.py
# If set to true - ensures that if a star import is present, nothing else is
# imported from that namespace.
combine_star=False
# If set to true - imports will be sorted by their length instead of
# alphabetically.
length_sort=False
# An integer that represents the longest line-length you want a single import to
# take. Defaults to 80.
line_length=119
# A comment to consistently place directly above future imports.
import_heading_future=Future
# A comment to consistently place directly above django imports.
import_heading_django=Django
# A comment to consistently place directly above imports from the standard library.
import_heading_stdlib=Standard Library
# A comment to consistently place directly above thirdparty imports.
import_heading_thirdparty=Third Party
# A comment to consistently place directly above wger imports.
import_heading_firstparty=wger
# A comment to consistently place directly above imports that start with '.'.
import_heading_localfolder=Local
# An integer that represents the number of spaces you would like to indent by or
# Tab to indent by a single tab.
indent=' '
# A list of imports that will be forced to display withing the first party
# category.
known_first_party=wger
known_django=django
# An integer that represents how you want imports to be displayed if their long
# enough to span multiple lines. A full definition of all possible modes can be
# found in isort's README.
multi_line_output=3
force_grid_wrap=True
# If set to true - isort will create separate sections withing "from" imports
# for CONSTANTS, Classes, and modules/functions.
order_by_type=True
# Forces a certain number of lines after the imports and before the first line
# of functional code. By default this is 2 lines if the first line of code is a
# class or function. Otherwise it's 1.
lines_after_imports=2
# If set to true - isort will combine as imports on the same line within for
# import statements. By default isort forces all as imports to display on their
# own lines.
combine_as_imports=True
# If set to true - isort will add imports even if the file specified is
# currently completely empty.
force_adds=False

View File

@@ -7,10 +7,13 @@
:license: GNU GPL, see LICENSE for more details.
"""
# Third Party
from setuptools import (
setup,
find_packages
find_packages,
setup
)
# wger
from wger import get_version
@@ -24,6 +27,7 @@ setup(
name='wger',
description='FLOSS workout, fitness and weight manager/tracker written with Django',
long_description=long_description,
long_description_content_type='text/x-rst',
version=get_version(),
url='https://github.com/wger-project',
author='Roland Geider',
@@ -39,13 +43,13 @@ setup(
'Framework :: Django',
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
install_requires=install_requires,
nstall_requires=install_requires,
entry_points={
'console_scripts': [
'wger = wger.__main__:main',

View File

@@ -5,7 +5,7 @@
:license: GNU GPL, see LICENSE for more details.
"""
VERSION = (1, 8, 0, 'beta', 1)
VERSION = (2, 0, 0, 'alpha', 1)
RELEASE = False
@@ -33,6 +33,6 @@ def get_version(version=None, release=None):
else:
sub = ''
if not release:
sub += '-dev'
sub += '.dev0'
return main + sub

View File

@@ -14,20 +14,27 @@
#
# You should have received a copy of the GNU Affero General Public License
# Standard Library
import os
import sys
# Third Party
from invoke import run
'''
"""
This simple wrapper script is used as a console entry point in the packaged
version of the application. It simply redirects all arguments to the invoke
command, which does all the work.
'''
"""
invoke_cmd = 'invoke '
def main():
# Change the working directory so that invoke can find the tasks fiel
os.chdir(os.path.dirname(os.path.abspath(__file__)))
args = sys.argv[1:]
if len(args):
run(invoke_cmd + ' '.join(args), pty=True)

View File

@@ -16,7 +16,9 @@
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# wger
from wger import get_version
VERSION = get_version()
default_app_config = 'wger.config.apps.ConfigConfig'

View File

@@ -14,6 +14,7 @@
#
# You should have received a copy of the GNU Affero General Public License
# Django
from django.apps import AppConfig

View File

@@ -1,9 +1,9 @@
[
{
"pk": 1,
"model": "config.gymconfig",
"pk": 1,
"model": "config.gymconfig",
"fields": {
"default_gym": null
}
}
]
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# flake8: noqa
from __future__ import unicode_literals
from django.db import models, migrations
@@ -16,7 +17,9 @@ class Migration(migrations.Migration):
name='GymConfig',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('default_gym', models.ForeignKey(blank=True, to='gym.Gym', help_text='Select the default gym for this installation. This will assign all new registered users to this gym and update all existing users without a gym.', null=True, verbose_name='Default gym')),
('default_gym', models.ForeignKey(blank=True, to='gym.Gym',
help_text='Select the default gym for this installation. This will assign all new registered users to this gym and update all existing users without a gym.',
null=True, verbose_name='Default gym', on_delete=models.CASCADE)),
],
options={
},
@@ -28,8 +31,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('item', models.CharField(max_length=2, editable=False, choices=[(b'1', 'Exercises'), (b'2', 'Ingredients')])),
('show', models.BooleanField(default=1)),
('language', models.ForeignKey(related_name='language_source', editable=False, to='core.Language')),
('language_target', models.ForeignKey(related_name='language_target', editable=False, to='core.Language')),
('language', models.ForeignKey(related_name='language_source', editable=False, to='core.Language', on_delete=models.CASCADE)),
('language_target', models.ForeignKey(related_name='language_target', editable=False, to='core.Language', on_delete=models.CASCADE)),
],
options={
'ordering': ['item', 'language_target'],

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# flake8: noqa
# Generated by Django 1.11.21 on 2019-06-18 16:17
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('config', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='languageconfig',
name='item',
field=models.CharField(
choices=[('1', 'Exercises'), ('2', 'Ingredients')], editable=False, max_length=2),
),
]

View File

@@ -15,30 +15,39 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Standard Library
import logging
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
# Django
from django.core.cache import cache
from wger.core.models import Language, UserProfile
from wger.gym.helpers import is_any_gym_admin
from wger.gym.models import Gym, GymUserConfig
from django.db import models
from django.utils.translation import ugettext_lazy as _
from wger.utils.cache import delete_template_fragment_cache
from wger.utils.cache import cache_mapper
# wger
from wger.core.models import (
Language,
UserProfile
)
from wger.gym.helpers import is_any_gym_admin
from wger.gym.models import (
Gym,
GymUserConfig
)
from wger.utils.cache import (
cache_mapper,
delete_template_fragment_cache
)
logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class LanguageConfig(models.Model):
'''
"""
Configuration for languages
Allows to specify what exercises and ingredients are shown for each language
'''
"""
SHOW_ITEM_EXERCISES = '1'
SHOW_ITEM_INGREDIENTS = '2'
SHOW_ITEM_LIST = (
@@ -48,31 +57,33 @@ class LanguageConfig(models.Model):
language = models.ForeignKey(Language,
related_name='language_source',
editable=False)
editable=False,
on_delete=models.CASCADE)
language_target = models.ForeignKey(Language,
related_name='language_target',
editable=False)
editable=False,
on_delete=models.CASCADE)
item = models.CharField(max_length=2,
choices=SHOW_ITEM_LIST,
editable=False)
show = models.BooleanField(default=1)
class Meta:
'''
"""
Set some other properties
'''
"""
ordering = ["item", "language_target", ]
def __str__(self):
'''
"""
Return a more human-readable representation
'''
"""
return u"Config for language {0}".format(self.language)
def save(self, *args, **kwargs):
'''
"""
Reset all cached infos
'''
"""
super(LanguageConfig, self).save(*args, **kwargs)
@@ -84,9 +95,9 @@ class LanguageConfig(models.Model):
delete_template_fragment_cache('exercise-overview', self.language_id)
def delete(self, *args, **kwargs):
'''
"""
Reset all cached infos
'''
"""
# Cached objects
cache.delete(cache_mapper.get_language_config_key(self.language, self.item))
@@ -98,14 +109,13 @@ class LanguageConfig(models.Model):
super(LanguageConfig, self).delete(*args, **kwargs)
@python_2_unicode_compatible
class GymConfig(models.Model):
'''
"""
System wide configuration for gyms
At the moment this only allows to set one gym as the default
TODO: close registration (users can only become members thorough an admin)
'''
"""
default_gym = models.ForeignKey(Gym,
verbose_name=_('Default gym'),
@@ -114,21 +124,22 @@ class GymConfig(models.Model):
'gym and update all existing users without a '
'gym.'),
null=True,
blank=True)
'''
blank=True,
on_delete=models.CASCADE)
"""
Default gym for the wger installation
'''
"""
def __str__(self):
'''
"""
Return a more human-readable representation
'''
"""
return u"Default gym {0}".format(self.default_gym)
def save(self, *args, **kwargs):
'''
"""
Perform additional tasks
'''
"""
if self.default_gym:
# All users that have no gym set in the profile are edited

View File

@@ -15,19 +15,21 @@
# You should have received a copy of the GNU Affero General Public License
# Django
from django.db.models.signals import post_save
from django.dispatch import receiver
# wger
from wger.config.models import LanguageConfig
from wger.core.models import Language
@receiver(post_save, sender=Language)
def init_language_config(sender, instance, created, **kwargs):
'''
"""
Creates language config entries when new languages are created
(all combinations of all languages)
'''
"""
for language_source in Language.objects.all():
for language_target in Language.objects.all():
if not LanguageConfig.objects.filter(language=language_source)\

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load i18n staticfiles wger_extras %}
{% load i18n static wger_extras %}
{% block title %}{% trans "Languages" %}{% endblock %}
@@ -8,7 +8,7 @@
<div class="list-group">
{% for language in language_list %}
<a href="{% url 'core:language:view' language.id %}" class="list-group-item">
<span class="glyphicon glyphicon-chevron-right pull-right"></span>
<span class="glyphicon glyphicon-chevron-right float-right"></span>
{{ language.full_name }}
</a>
{% empty %}

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load i18n staticfiles wger_extras django_bootstrap_breadcrumbs %}
{% load i18n static wger_extras django_bootstrap_breadcrumbs %}
{% block title %}{{ view_language }}{% endblock %}
@@ -85,24 +85,22 @@ in A).{% endblocktrans %}</p>
{# #}
{% block options %}
<div class="btn-group">
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="{% fa_class 'cog' %}"></span>
{% trans "Options" %}
</button>
<ul class="dropdown-menu">
<li>
<a href="{% url 'core:language:edit' view_language.id %}" class="wger-modal-dialog">
<span class="{% fa_class 'pencil-square-o' %}"></span>
<div class="btn-group">
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="{% fa_class 'cog' %}"></span>
{% trans "Options" %}
</button>
<div class="dropdown-menu">
<a href="{% url 'core:language:edit' view_language.id %}" class="wger-modal-dialog dropdown-item">
<span class="{% fa_class 'edit' %}"></span>
{% trans "Edit" %}
</a>
</li>
<li role="separator" class="divider"></li>
<li>
<a href="{% url 'core:language:delete' view_language.id %}" class="wger-modal-dialog">
<div role="separator" class="dropdown-divider"></div>
<a href="{% url 'core:language:delete' view_language.id %}" class="wger-modal-dialog dropdown-item">
<span class="{% fa_class 'trash' %}"></span>
{% trans "Delete" %}
</a>
</li>
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@@ -15,16 +15,18 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
from django.core.urlresolvers import reverse
# Django
from django.urls import reverse
# wger
from wger.core.tests.base_testcase import WgerTestCase
from wger.gym.models import Gym
from wger.core.tests.base_testcase import WorkoutManagerTestCase
class GymNameHeaderTestCase(WorkoutManagerTestCase):
'''
class GymNameHeaderTestCase(WgerTestCase):
"""
Test case for showing gym name on application header
'''
"""
def check_header(self, gym=None):
@@ -32,9 +34,9 @@ class GymNameHeaderTestCase(WorkoutManagerTestCase):
self.assertEqual(response.context['custom_header'], gym)
def test_custom_header_gym_members(self):
'''
"""
Test the custom header for gym members
'''
"""
# Gym 1, custom header activated
gym = Gym.objects.get(pk=1)
@@ -60,7 +62,7 @@ class GymNameHeaderTestCase(WorkoutManagerTestCase):
self.check_header(gym=None)
def test_custom_header_anonymous_user(self):
'''
"""
Test the custom header for logged out users
'''
"""
self.check_header(gym=None)

View File

@@ -15,24 +15,29 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Django
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.urls import reverse
# wger
from wger.config.models import GymConfig
from wger.core.models import UserProfile
from wger.core.tests.base_testcase import WorkoutManagerTestCase
from wger.gym.models import Gym, GymUserConfig
from wger.core.tests.base_testcase import WgerTestCase
from wger.gym.models import (
Gym,
GymUserConfig
)
class GymConfigTestCase(WorkoutManagerTestCase):
'''
class GymConfigTestCase(WgerTestCase):
"""
Test the system wide gym configuration
'''
"""
def test_default_gym(self):
'''
"""
Test that newly registered users get a gym
'''
"""
gym = Gym.objects.get(pk=2)
gym_config = GymConfig.objects.get(pk=1)
@@ -41,20 +46,21 @@ class GymConfigTestCase(WorkoutManagerTestCase):
# Register
registration_data = {'username': 'myusername',
'password1': 'secret',
'password2': 'secret',
'password1': 'Aerieth4yuv5',
'password2': 'Aerieth4yuv5',
'email': 'my.email@example.com',
'g-recaptcha-response': 'PASSED', }
self.client.post(reverse('core:user:registration'), registration_data)
response = self.client.post(reverse('core:user:registration'), registration_data)
self.assertEqual(response.status_code, 302)
new_user = User.objects.all().last()
self.assertEqual(new_user.userprofile.gym, gym)
self.assertEqual(new_user.gymuserconfig.gym, gym)
def test_no_default_gym(self):
'''
"""
Test the user registration without a default gym
'''
"""
gym_config = GymConfig.objects.get(pk=1)
gym_config.default_gym = None
@@ -62,20 +68,21 @@ class GymConfigTestCase(WorkoutManagerTestCase):
# Register
registration_data = {'username': 'myusername',
'password1': 'secret',
'password2': 'secret',
'password1': 'Iem2ahl1eizo',
'password2': 'Iem2ahl1eizo',
'email': 'my.email@example.com',
'g-recaptcha-response': 'PASSED', }
self.client.post(reverse('core:user:registration'), registration_data)
response = self.client.post(reverse('core:user:registration'), registration_data)
self.assertEqual(response.status_code, 302)
new_user = User.objects.all().last()
self.assertEqual(new_user.userprofile.gym_id, None)
self.assertRaises(GymUserConfig.DoesNotExist, GymUserConfig.objects.get, user=new_user)
def test_update_userprofile(self):
'''
"""
Test setting the gym for users when setting a default gym
'''
"""
UserProfile.objects.update(gym=None)
GymUserConfig.objects.all().delete()

View File

@@ -15,15 +15,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# wger
from wger.config.models import LanguageConfig
from wger.core.tests.base_testcase import WorkoutManagerEditTestCase
from wger.core.tests.base_testcase import WgerEditTestCase
class EditLanguageConfigTestCase(WorkoutManagerEditTestCase):
'''
class EditLanguageConfigTestCase(WgerEditTestCase):
"""
Tests editing a language config
'''
"""
object_class = LanguageConfig
url = 'config:language_config:edit'

View File

@@ -15,25 +15,32 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import patterns, url, include
# Django
from django.conf.urls import (
include,
url
)
from wger.config.views import language_config
from wger.config.views import gym_config
# wger
from wger.config.views import (
gym_config,
language_config
)
# sub patterns for language configs
patterns_language_config = [
url(r'^(?P<pk>\d+)/edit',
language_config.LanguageConfigUpdateView.as_view(),
name='edit'),
url(r'^(?P<pk>\d+)/edit',
language_config.LanguageConfigUpdateView.as_view(),
name='edit'),
]
# sub patterns for default gym
patterns_gym_config = [
url(r'^edit$',
gym_config.GymConfigUpdateView.as_view(),
name='edit'),
url(r'^edit$',
gym_config.GymConfigUpdateView.as_view(),
name='edit'),
]
@@ -41,6 +48,6 @@ patterns_gym_config = [
# Actual patterns
#
urlpatterns = [
url(r'^language-config/', include(patterns_language_config, namespace="language_config")),
url(r'^gym-config/', include(patterns_gym_config, namespace="gym_config")),
url(r'^language-config/', include((patterns_language_config, 'language_config'), namespace="language_config")),
url(r'^gym-config/', include((patterns_gym_config, 'gym_config'), namespace="gym_config")),
]

View File

@@ -14,12 +14,15 @@
#
# You should have received a copy of the GNU Affero General Public License
# Standard Library
import logging
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext as _
# Django
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy
from django.views.generic import UpdateView
# wger
from wger.config.models import GymConfig
from wger.utils.generic_views import WgerFormMixin
@@ -28,22 +31,17 @@ logger = logging.getLogger(__name__)
class GymConfigUpdateView(WgerFormMixin, UpdateView):
'''
"""
Generic view to edit the gym config table
'''
"""
model = GymConfig
fields = '__all__'
permission_required = 'config.change_gymconfig'
success_url = reverse_lazy('gym:gym:list')
title = ugettext_lazy('Edit')
def get_object(self):
'''
"""
Return the only gym config object
'''
"""
return GymConfig.objects.get(pk=1)
def get_context_data(self, **kwargs):
context = super(GymConfigUpdateView, self).get_context_data(**kwargs)
context['form_action'] = reverse('config:gym_config:edit')
context['title'] = _('Edit')
return context

View File

@@ -14,13 +14,19 @@
#
# You should have received a copy of the GNU Affero General Public License
# Standard Library
import logging
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext as _
# Django
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin
)
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy
from django.views.generic import UpdateView
# wger
from wger.config.models import LanguageConfig
from wger.utils.generic_views import WgerFormMixin
@@ -32,23 +38,16 @@ class LanguageConfigUpdateView(WgerFormMixin,
LoginRequiredMixin,
PermissionRequiredMixin,
UpdateView):
'''
"""
Generic view to edit a language config
'''
"""
model = LanguageConfig
fields = ['show']
permission_required = 'config.change_languageconfig'
title = ugettext_lazy('Edit')
def get_success_url(self):
'''
"""
Return to the language page
'''
"""
return reverse_lazy('core:language:view', kwargs={'pk': self.object.language_id})
def get_context_data(self, **kwargs):
context = super(LanguageConfigUpdateView, self).get_context_data(**kwargs)
context['form_action'] = reverse('config:language_config:edit',
kwargs={'pk': self.object.id})
context['title'] = _('Edit')
return context

View File

@@ -16,7 +16,9 @@
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# wger
from wger import get_version
VERSION = get_version()
default_app_config = 'wger.core.apps.CoreConfig'

View File

@@ -1,79 +0,0 @@
# -*- coding: utf-8 -*-
# This file is part of wger Workout Manager.
#
# wger Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# wger Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
from tastypie.authentication import ApiKeyAuthentication
from tastypie.constants import ALL
from tastypie.resources import ModelResource
from wger.utils.resources import UserObjectsOnlyAuthorization
from wger.core.models import (
UserProfile,
Language,
DaysOfWeek,
License
)
class UserProfileResource(ModelResource):
'''
Resource for user profiles
'''
def authorized_read_list(self, object_list, bundle):
'''
Filter to own objects
'''
return object_list.filter(user=bundle.request.user)
class Meta:
excludes = ('is_temporary', )
queryset = UserProfile.objects.all()
authentication = ApiKeyAuthentication()
authorization = UserObjectsOnlyAuthorization()
class LanguageResource(ModelResource):
'''
Resource for languages
'''
class Meta:
queryset = Language.objects.all()
filtering = {'id': ALL,
"full_name": ALL,
"short_name": ALL}
class DaysOfWeekResource(ModelResource):
'''
Resource for days of the week
'''
class Meta:
queryset = DaysOfWeek.objects.all()
filtering = {'id': ALL,
'day_of_week': ALL}
class LicenseResource(ModelResource):
'''
Resource for licenses
'''
class Meta:
queryset = License.objects.all()
filtering = {'id': ALL,
"full_name": ALL,
"short_name": ALL,
"url": ALL}

View File

@@ -15,67 +15,76 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Third Party
from rest_framework import serializers
# wger
from wger.core.models import (
UserProfile,
Language,
DaysOfWeek,
Language,
License,
RepetitionUnit,
WeightUnit)
UserProfile,
WeightUnit
)
class UserprofileSerializer(serializers.ModelSerializer):
'''
"""
Workout session serializer
'''
"""
class Meta:
model = UserProfile
fields = '__all__'
class UsernameSerializer(serializers.Serializer):
'''
"""
Serializer to extract the username
'''
"""
username = serializers.CharField()
class LanguageSerializer(serializers.ModelSerializer):
'''
"""
Language serializer
'''
"""
class Meta:
model = Language
fields = '__all__'
class DaysOfWeekSerializer(serializers.ModelSerializer):
'''
"""
DaysOfWeek serializer
'''
"""
class Meta:
model = DaysOfWeek
fields = '__all__'
class LicenseSerializer(serializers.ModelSerializer):
'''
"""
License serializer
'''
"""
class Meta:
model = License
fields = '__all__'
class RepetitionUnitSerializer(serializers.ModelSerializer):
'''
"""
Repetition unit serializer
'''
"""
class Meta:
model = RepetitionUnit
fields = '__all__'
class WeightUnitSerializer(serializers.ModelSerializer):
'''
"""
Weight unit serializer
'''
"""
class Meta:
model = WeightUnit
fields = '__all__'

View File

@@ -15,109 +15,117 @@
# You should have received a copy of the GNU Affero General Public License
# along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Django
from django.contrib.auth.models import User
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.decorators import detail_route
from wger.core.models import (
UserProfile,
Language,
DaysOfWeek,
License,
RepetitionUnit,
WeightUnit)
# Third Party
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
# wger
from wger.core.api.serializers import (
UsernameSerializer,
LanguageSerializer,
DaysOfWeekSerializer,
LanguageSerializer,
LicenseSerializer,
RepetitionUnitSerializer,
UsernameSerializer,
UserprofileSerializer,
WeightUnitSerializer
)
from wger.core.api.serializers import UserprofileSerializer
from wger.utils.permissions import UpdateOnlyPermission, WgerPermission
from wger.core.models import (
DaysOfWeek,
Language,
License,
RepetitionUnit,
UserProfile,
WeightUnit
)
from wger.utils.permissions import (
UpdateOnlyPermission,
WgerPermission
)
class UserProfileViewSet(viewsets.ModelViewSet):
'''
"""
API endpoint for workout objects
'''
"""
is_private = True
serializer_class = UserprofileSerializer
permission_classes = (WgerPermission, UpdateOnlyPermission)
ordering_fields = '__all__'
def get_queryset(self):
'''
"""
Only allow access to appropriate objects
'''
"""
return UserProfile.objects.filter(user=self.request.user)
def get_owner_objects(self):
'''
"""
Return objects to check for ownership permission
'''
"""
return [(User, 'user')]
@detail_route()
@action(detail=True)
def username(self, request, pk):
'''
"""
Return the username
'''
"""
user = self.get_object().user
return Response(UsernameSerializer(user).data)
class LanguageViewSet(viewsets.ReadOnlyModelViewSet):
'''
"""
API endpoint for workout objects
'''
"""
queryset = Language.objects.all()
serializer_class = LanguageSerializer
ordering_fields = '__all__'
filter_fields = ('full_name',
'short_name')
filterset_fields = ('full_name',
'short_name')
class DaysOfWeekViewSet(viewsets.ReadOnlyModelViewSet):
'''
"""
API endpoint for workout objects
'''
"""
queryset = DaysOfWeek.objects.all()
serializer_class = DaysOfWeekSerializer
ordering_fields = '__all__'
filter_fields = ('day_of_week', )
filterset_fields = ('day_of_week', )
class LicenseViewSet(viewsets.ReadOnlyModelViewSet):
'''
"""
API endpoint for workout objects
'''
"""
queryset = License.objects.all()
serializer_class = LicenseSerializer
ordering_fields = '__all__'
filter_fields = ('full_name',
'short_name',
'url')
filterset_fields = ('full_name',
'short_name',
'url')
class RepetitionUnitViewSet(viewsets.ReadOnlyModelViewSet):
'''
"""
API endpoint for repetition units objects
'''
"""
queryset = RepetitionUnit.objects.all()
serializer_class = RepetitionUnitSerializer
ordering_fields = '__all__'
filter_fields = ('name', )
filterset_fields = ('name', )
class WeightUnitViewSet(viewsets.ReadOnlyModelViewSet):
'''
"""
API endpoint for weight units objects
'''
"""
queryset = WeightUnit.objects.all()
serializer_class = WeightUnitSerializer
ordering_fields = '__all__'
filter_fields = ('name', )
filterset_fields = ('name', )

View File

@@ -14,6 +14,7 @@
#
# You should have received a copy of the GNU Affero General Public License
# Django
from django.apps import AppConfig, apps

View File

@@ -14,44 +14,47 @@
#
# You should have received a copy of the GNU Affero General Public License
# Standard Library
import datetime
import logging
import random
import datetime
import uuid
from django.contrib.auth.models import User
# Django
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from wger.weight.models import WeightEntry
from wger.exercises.models import Exercise
# wger
from wger.core.models import DaysOfWeek
from wger.exercises.models import Exercise
from wger.manager.models import (
Workout,
Day,
Schedule,
ScheduleStep,
Set,
Setting,
WorkoutLog,
Schedule,
ScheduleStep
Workout,
WorkoutLog
)
from wger.nutrition.models import (
NutritionPlan,
Ingredient,
IngredientWeightUnit,
Meal,
MealItem,
Ingredient,
IngredientWeightUnit
NutritionPlan
)
from wger.utils.language import load_language
from wger.weight.models import WeightEntry
logger = logging.getLogger(__name__)
def create_temporary_user():
'''
"""
Creates a temporary user
'''
"""
username = uuid.uuid4().hex[:-2]
password = uuid.uuid4().hex[:-2]
email = ''
@@ -68,9 +71,9 @@ def create_temporary_user():
def create_demo_entries(user):
'''
"""
Creates some demo data for temporary users
'''
"""
# (this is a bit ugly and long...)
language = load_language()

View File

@@ -1,51 +1,51 @@
[
{
"pk": 1,
"model": "core.daysofweek",
"pk": 1,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Monday"
}
},
},
{
"pk": 2,
"model": "core.daysofweek",
"pk": 2,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Tuesday"
}
},
},
{
"pk": 3,
"model": "core.daysofweek",
"pk": 3,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Wednesday"
}
},
},
{
"pk": 4,
"model": "core.daysofweek",
"pk": 4,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Thursday"
}
},
},
{
"pk": 5,
"model": "core.daysofweek",
"pk": 5,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Friday"
}
},
},
{
"pk": 6,
"model": "core.daysofweek",
"pk": 6,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Saturday"
}
},
},
{
"pk": 7,
"model": "core.daysofweek",
"pk": 7,
"model": "core.daysofweek",
"fields": {
"day_of_week": "Sunday"
}
}
]
]

View File

@@ -323,12 +323,12 @@
"permissions": [
[
"add_log",
"email",
"mailer",
"log"
],
[
"change_log",
"email",
"mailer",
"log"
],
[
@@ -562,4 +562,4 @@
"model": "auth.group",
"pk": 6
}
]
]

View File

@@ -1,90 +1,98 @@
[
{
"model": "core.language",
"pk": 1,
"fields": {
"short_name": "de",
"full_name": "Deutsch"
},
"model": "core.language",
"pk": 1
}
},
{
"model": "core.language",
"pk": 2,
"fields": {
"short_name": "en",
"full_name": "English"
},
"model": "core.language",
"pk": 2
}
},
{
"model": "core.language",
"pk": 3,
"fields": {
"short_name": "bg",
"full_name": "\u0431\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438 \u0435\u0437\u0438\u043a"
},
"model": "core.language",
"pk": 3
}
},
{
"model": "core.language",
"pk": 4,
"fields": {
"short_name": "es",
"full_name": "Espa\u00f1ol"
},
"model": "core.language",
"pk": 4
}
},
{
"model": "core.language",
"pk": 5,
"fields": {
"short_name": "ru",
"full_name": "\u0420\u0443\u0441\u0441\u043a\u0438\u0439"
},
"model": "core.language",
"pk": 5
}
},
{
"model": "core.language",
"pk": 6,
"fields": {
"short_name": "nl",
"full_name": "Nederlands"
},
"model": "core.language",
"pk": 6
}
},
{
"model": "core.language",
"pk": 7,
"fields": {
"short_name": "pt",
"full_name": "Portugu\u00eas"
},
"model": "core.language",
"pk": 7
}
},
{
"model": "core.language",
"pk": 8,
"fields": {
"short_name": "el",
"full_name": "\u03b5\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac"
},
"model": "core.language",
"pk": 8
}
},
{
"model": "core.language",
"pk": 9,
"fields": {
"short_name": "cs",
"full_name": "\u010de\u0161tina"
},
"model": "core.language",
"pk": 9
}
},
{
"model": "core.language",
"pk": 10,
"fields": {
"short_name": "sv",
"full_name": "Svenska"
},
"model": "core.language",
"pk": 10
}
},
{
"model": "core.language",
"pk": 11,
"fields": {
"short_name": "no",
"full_name": "Norsk"
},
}
},
{
"model": "core.language",
"pk": 11
"pk": 12,
"fields": {
"short_name": "fr",
"full_name": "Fran\u00e7ais"
}
}
]
]

View File

@@ -1,37 +1,37 @@
[
{
"pk": 1,
"model": "core.license",
"pk": 1,
"model": "core.license",
"fields": {
"url": "https://creativecommons.org/licenses/by-sa/3.0/deed.en",
"full_name": " Creative Commons Attribution Share Alike 3",
"url": "https://creativecommons.org/licenses/by-sa/3.0/deed.en",
"full_name": " Creative Commons Attribution Share Alike 3",
"short_name": "CC-BY-SA 3"
}
},
},
{
"pk": 2,
"model": "core.license",
"pk": 2,
"model": "core.license",
"fields": {
"url": "https://creativecommons.org/licenses/by-sa/4.0/deed.en",
"full_name": "Creative Commons Attribution Share Alike 4",
"url": "https://creativecommons.org/licenses/by-sa/4.0/deed.en",
"full_name": "Creative Commons Attribution Share Alike 4",
"short_name": "CC-BY-SA 4"
}
},
},
{
"pk": 3,
"model": "core.license",
"pk": 3,
"model": "core.license",
"fields": {
"url": "http://creativecommons.org/publicdomain/zero/1.0/",
"full_name": "Creative Commons Public Domain 1.0",
"url": "http://creativecommons.org/publicdomain/zero/1.0/",
"full_name": "Creative Commons Public Domain 1.0",
"short_name": "CC0"
}
},
{
"pk": 4,
"model": "core.license",
"pk": 4,
"model": "core.license",
"fields": {
"url": "http://creativecommons.org/licenses/by/4.0/",
"full_name": "Creative Commons Attribution 4",
"url": "http://creativecommons.org/licenses/by/4.0/",
"full_name": "Creative Commons Attribution 4",
"short_name": "CC-BY 4"
}
}

View File

@@ -1,19 +1,19 @@
[
{
"pk": 1,
"model": "core.license",
"pk": 1,
"model": "core.license",
"fields": {
"url": "",
"full_name": "A cool and free license - Germany",
"url": "",
"full_name": "A cool and free license - Germany",
"short_name": "ACAFL - DE"
}
},
},
{
"pk": 2,
"model": "core.license",
"pk": 2,
"model": "core.license",
"fields": {
"url": "https://another-cool-license.org/acl-2.1",
"full_name": "Another cool license 2.1",
"url": "https://another-cool-license.org/acl-2.1",
"full_name": "Another cool license 2.1",
"short_name": "ACL 2.1"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[
{
"pk": 1,
"pk": 1,
"model": "auth.user",
"fields": {
"username": "admin",
@@ -34,12 +34,12 @@
}
},
{
"pk": 1,
"model": "core.userprofile",
"pk": 1,
"model": "core.userprofile",
"fields": {
"is_temporary": false,
"show_comments": false,
"show_english_ingredients": false,
"is_temporary": false,
"show_comments": false,
"show_english_ingredients": false,
"user": 1,
"gym": 1
}

View File

@@ -14,32 +14,71 @@
#
# You should have received a copy of the GNU Affero General Public License
from captcha.fields import ReCaptchaField
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
# Django
from django import forms
from django.contrib.auth.forms import (
AuthenticationForm,
UserCreationForm
)
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django import forms
from django.forms import (
CharField,
EmailField,
Form,
CharField,
widgets,
PasswordInput
PasswordInput,
widgets
)
from django.utils.translation import ugettext as _
# Third Party
from captcha.fields import ReCaptchaField
from crispy_forms.bootstrap import (
Accordion,
AccordionGroup
)
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (
ButtonHolder,
Column,
Layout,
Row,
Submit
)
# wger
from wger.core.models import UserProfile
class UserLoginForm(AuthenticationForm):
'''
"""
Form for logins
"""
Overwritten here just to change the label on the 'username' field
'''
username = forms.CharField(label=_("Username or email"), max_length=254)
def __init__(self, *args, **kwargs):
super(UserLoginForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit('submit', _('Login'), css_class='btn-success btn-block'))
self.helper.form_class = 'wger-form'
self.helper.layout = Layout(
Row(
Column('username', css_class='form-group col-6 mb-0'),
Column('password', css_class='form-group col-6 mb-0'),
css_class='form-row'
)
)
class UserPreferencesForm(forms.ModelForm):
first_name = forms.CharField(label=_('First name'),
required=False)
last_name = forms.CharField(label=_('Last name'),
required=False)
email = EmailField(label=_("Email"),
help_text=_("Used for password resets and, optionally, email reminders."),
required=False)
class Meta:
model = UserProfile
fields = ('show_comments',
@@ -52,7 +91,43 @@ class UserPreferencesForm(forms.ModelForm):
'timer_active',
'timer_pause',
'ro_access',
'num_days_weight_reminder')
'num_days_weight_reminder',
'birthdate'
)
def __init__(self, *args, **kwargs):
super(UserPreferencesForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'wger-form'
self.helper.layout = Layout(
Accordion(
AccordionGroup(_("Personal data"),
'email',
Row(Column('first_name', css_class='form-group col-6 mb-0'),
Column('last_name', css_class='form-group col-6 mb-0'),
css_class='form-row'),
),
AccordionGroup(_("Workout reminders"),
'workout_reminder_active',
'workout_reminder',
'workout_duration',
),
AccordionGroup("{} ({})".format(_("Gym mode"), _("mobile version only")),
"timer_active",
"timer_pause"
),
AccordionGroup(_("Other settings"),
"ro_access",
"notification_language",
"weight_unit",
"show_comments",
"show_english_ingredients",
"num_days_weight_reminder",
"birthdate",
)
),
ButtonHolder(Submit('submit', _("Save"), css_class='btn-success btn-block'))
)
class UserEmailForm(forms.ModelForm):
@@ -65,14 +140,14 @@ class UserEmailForm(forms.ModelForm):
fields = ('email', )
def clean_email(self):
'''
"""
Email must be unique system wide
However, this check should only be performed when the user changes his
email, otherwise the uniqueness check will because it will find one user
(the current one) using the same email. Only when the user changes it, do
we want to check that nobody else has that email
'''
"""
email = self.cleaned_data["email"]
if not email:
@@ -99,12 +174,12 @@ class UserPersonalInformationForm(UserEmailForm):
class PasswordConfirmationForm(Form):
'''
"""
A simple password confirmation form.
This can be used to make sure the user really wants to perform a dangerous
action. The form must be initialised with a user object.
'''
"""
password = CharField(label=_("Password"),
widget=PasswordInput,
help_text=_('Please enter your current password.'))
@@ -112,11 +187,16 @@ class PasswordConfirmationForm(Form):
def __init__(self, user, data=None):
self.user = user
super(PasswordConfirmationForm, self).__init__(data=data)
self.helper = FormHelper()
self.helper.layout = Layout(
'password',
ButtonHolder(Submit('submit', _("Delete"), css_class='btn-danger btn-block'))
)
def clean_password(self):
'''
"""
Check that the password supplied matches the one for the user
'''
"""
password = self.cleaned_data.get('password', None)
if not self.user.check_password(password):
raise ValidationError(_('Invalid password'))
@@ -124,34 +204,43 @@ class PasswordConfirmationForm(Form):
class RegistrationForm(UserCreationForm, UserEmailForm):
'''
"""
Registration form
'''
"""
# Manually set the language to 'en', otherwise the language used seems to
# randomly one of the application languages. This also appears to happen
# only on wger.de, perhaps because there the application is behind a reverse
# proxy. See #281.
captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'en'},
label=_('Confirmation text'),
captcha = ReCaptchaField(label=_('Confirmation text'),
help_text=_('As a security measure, please enter the previous words'))
class RegistrationFormNoCaptcha(UserCreationForm, UserEmailForm):
'''
"""
Registration form without captcha field
"""
This is used when registering through an app, in that case there is not
such a spam danger and simplifies the registration process on a mobile
device.
'''
pass
def __init__(self, *args, **kwargs):
super(RegistrationFormNoCaptcha, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'wger-form'
self.helper.layout = Layout(
'username',
'email',
Row(
Column('password1', css_class='form-group col-6 mb-0'),
Column('password2', css_class='form-group col-6 mb-0'),
css_class='form-row'
),
ButtonHolder(Submit('submit', _("Register"), css_class='btn-success btn-block'))
)
class FeedbackRegisteredForm(forms.Form):
'''
"""
Feedback form used for logged in users
'''
"""
contact = forms.CharField(max_length=50,
min_length=10,
label=_('Contact'),
@@ -167,9 +256,8 @@ class FeedbackRegisteredForm(forms.Form):
class FeedbackAnonymousForm(FeedbackRegisteredForm):
'''
"""
Feedback form used for anonymous users (has additionally a reCaptcha field)
'''
captcha = ReCaptchaField(attrs={'theme': 'clean'},
label=_('Confirmation text'),
"""
captcha = ReCaptchaField(label=_('Confirmation text'),
help_text=_('As a security measure, please enter the previous words'),)

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