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 insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
# Docstrings and comments use max_line_length = 79 #
[*.py] # Javascript
max_line_length = 100 #
[*.js] [*.js]
indent_size = 2 indent_size = 2
[.eslintignore] [{.eslintrc,.eslintignore}]
indent_size = 2 indent_size = 2
#
# Python
#
[*.py]
max_line_length = 100
#
# JSON File
#
[*.json] [*.json]
indent_size = 2 indent_size = 2
#
# YAML File
#
[*.yml] [*.yml]
indent_size = 2 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 # Bash scripts (e.g. in Docker) make problems when the line ending is not LF
* text=auto * 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": { "env": {
"browser": true, "browser": true,
"jquery": 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 # IDE
.idea/ .idea/
# External Libraries # External Libraries
wger/core/static/bower_components wger/core/static/yarn
node_modules 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 language: python
dist: bionic
services:
- postgresql
# Cache the pip files # Cache the pip files
cache: cache:
@@ -8,60 +12,43 @@ cache:
- node_modules - node_modules
- wger/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 versions to test
python: python:
- "2.7" - "3.6"
- "3.4" - "3.7"
- "3.5" - "3.8"
node_js: 10
# Manually define here the combinations environment variables to test
# https://github.com/travis-ci/travis-ci/issues/1519
env: env:
- TEST_MOBILE=True DB=postgresql TRAVIS_NODE_VERSION="4" - DB=postgresql
- TEST_MOBILE=True DB=sqlite TRAVIS_NODE_VERSION="4" - DB=sqlite
- TEST_MOBILE=False DB=postgresql TRAVIS_NODE_VERSION="4"
- TEST_MOBILE=False DB=sqlite TRAVIS_NODE_VERSION="4"
# Install the application # Install the application
install: 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 # Install requirements
- pip install -r requirements_devel.txt - pip install -r requirements_devel.txt
- npm install - python setup.py develop
- cd wger
- if [[ "$DB" = "postgresql" ]]; then pip install psycopg2; fi - if [[ "$DB" = "postgresql" ]]; then pip install psycopg2; fi
# Setup application # Setup application
- if [[ "$DB" = "sqlite" ]]; then invoke create_settings; fi - if [[ "$DB" = "sqlite" ]]; then wger create-settings; fi
- if [[ "$DB" = "postgresql" ]]; then invoke create_settings --database-type postgresql; fi - if [[ "$DB" = "postgresql" ]]; then wger create-settings --database-type postgresql; fi
# change back to the source folder
- cd ..
# Create test databases # Create test databases
before_script: 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 - if [[ "$DB" = "postgresql" ]]; then psql -c 'CREATE DATABASE test_wger;' -U postgres; fi
# Do the tests # Do the tests
script: script:
# Formatting
- pep8 wger
# Javascript linting
- gulp lint
# Regular application # Regular application
- coverage run --source='.' ./manage.py test - coverage run --source='.' ./manage.py test --parallel
# Code coverage # Code coverage
- coverage report - 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 * Peter van der Does: https://github.com/petervanderdoes
* Malcolm Jones: https://github.com/DevloperMal * Malcolm Jones: https://github.com/DevloperMal
* Boniface Mwenda: https://github.com/andela-bmwenda * Boniface Mwenda: https://github.com/andela-bmwenda
* Scott Peshak: https://github.com/speshak
Translators Translators
----------- -----------

View File

@@ -1,24 +1,21 @@
# Files in root folder
include README.rst include README.rst
include AUTHORS.txt include AUTHORS.txt
include AGPL.txt include AGPL.txt
include CC-BY-SA.txt include CC-BY-SA.txt
include requirements.txt include requirements.txt
include tasks.py include requirements_devel.txt
# Application folder as well as extras
recursive-include extras *.*
recursive-include wger *.* recursive-include wger *.*
recursive-exclude wger *.pyc recursive-exclude wger *.pyc
recursive-exclude wger *.swp recursive-exclude wger *.swp
recursive-exclude wger *~ recursive-exclude wger *~
include extras/docker/*/Dockerfile
# added by check_manifest.py # Documentation
include *.rst
include *.txt
recursive-include docs *.bat recursive-include docs *.bat
recursive-include docs *.py recursive-include docs *.py
recursive-include docs *.rst recursive-include docs *.rst
recursive-include docs Makefile 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 wger
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. 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 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 system. There are more detailed instructions, other deployment options as well
as an administration guide available at https://wger.readthedocs.io or locally 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 in your code repository in the docs folder.
_build/index.html).
Please consult the commands' help for further information and available Please consult the commands' help for further information and available
parameters. parameters.
@@ -25,7 +24,8 @@ parameters.
Docker 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 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:: Then install the python packages from pypi in the virtualenv::
$ virtualenv --python python3 venv-django $ python3 -m venv venv-wger
$ source venv-django/bin/activate $ source venv-wger/bin/activate
2) Start the application. This will download the required JS and CSS libraries 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 $ git clone https://github.com/wger-project/wger.git
$ cd wger $ cd wger
$ pip install -r requirements.txt # or requirements_devel.txt to develop $ pip install -r requirements.txt
$ invoke create_settings \ $ python setup.py develop
--settings-path /home/wger/wger/settings.py \ $ wger create-settings --settings-path $(pwd)/settings.py --database-path $(pwd)/database.sqlite
--database-path /home/wger/wger/database.sqlite $ wger bootstrap --settings-path $(pwd)/settings.py --no-start-server
$ invoke bootstrap_wger \
--settings-path /home/wger/wger/settings.py \
--no-start-server
$ python manage.py runserver $ python manage.py runserver
3) Log in as: **admin**, password **admin** 3) Log in as: **admin**, password **admin**
After the first run you can just use django's development server. You will After the first run you just start django's development server::
probably want to move the settings and sqlite files to your git folder, see
the comments in the documentation (development chapter) about this::
$ python manage.py runserver $ 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) 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 $ sudo apt-get install python3-dev nodejs npm git
$ virtualenv venv-django $ sudo npm install -g yarn
$ source venv-django/bin/activate $ python3 -m venv venv-wger
$ source venv-wger/bin/activate
$ pip install wger $ pip install wger
2) Start the application. This will download the required JS and CSS libraries 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. 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 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 Available tasks:
``invoke`` (if installed from source) are the following (use e.g. ``wger
<command>``::
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 You can also get help on a specific command with ``wger --help <command>``.
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
Contact 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 report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway. file a bug anyway.
* **twitter:** https://twitter.com/wger_de * **gitter:** https://gitter.im/wger-project/wger
* **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 * **issue tracker:** https://github.com/wger-project/wger/issues
* **twitter:** https://twitter.com/wger_project
Sources Sources
@@ -173,29 +139,28 @@ Sources
All the code and the content is freely available: All the code and the content is freely available:
* **Main repository:** https://github.com/wger-project/wger * **Main repository:** https://github.com/wger-project/wger
* **Mirror:** https://bitbucket.org/rolandgeider/wger
Donations 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 help and support the project you are more than welcome to donate an amount of
your choice. your choice.
.. image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif .. 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 :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+). later (AGPL 3+).
The initial exercise and ingredient data is licensed additionally under one of The initial exercise and ingredient data is licensed additionally under one of
the Creative Commons licenses, see the individual exercises for more details. 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. 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. folders for more details.

View File

@@ -1,9 +1,113 @@
Changelog Changelog
========= =========
1.8 - IN DEVELOPMENT 2.0 - IN DEVELOPMENT
-------------------- **2020-xx-xx**
**2016-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: Upgrade steps from 1.7:
@@ -22,6 +126,7 @@ Upgrade steps from 1.7:
New languages: New languages:
* Norwegian (many thanks to Kjetil Elde `@w00p`_ `#304`_) * Norwegian (many thanks to Kjetil Elde `@w00p`_ `#304`_)
* French (many thanks to all translators)
New features: New features:
@@ -43,6 +148,7 @@ Improvements:
* Give feedback when autocompleter didn't find any results `#293`_ * Give feedback when autocompleter didn't find any results `#293`_
* Make exercise names links to their detail page in training log pages `#350`_ * Make exercise names links to their detail page in training log pages `#350`_
* Better GUI consistency in modal dialogs (thanks `@jstoebel`_ ) `#274`_ * 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`_ * 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`_) * New, more verbose, API endpoint for exercises, (thanks `@andela-bmwenda`_)
* The dashboard page was improved and made more user friendly `#201`_ (partly) * 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 .. _#243: https://github.com/wger-project/wger/issues/243
.. _#248: https://github.com/wger-project/wger/issues/248 .. _#248: https://github.com/wger-project/wger/issues/248
.. _#247: https://github.com/wger-project/wger/issues/247 .. _#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 .. _#263: https://github.com/wger-project/wger/issues/263
.. _#269: https://github.com/wger-project/wger/issues/269 .. _#269: https://github.com/wger-project/wger/issues/269
.. _#272: https://github.com/wger-project/wger/issues/272 .. _#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 .. _@alokhan: https://github.com/alokhan
.. _@w00p: https://github.com/w00p .. _@w00p: https://github.com/w00p
.. _@andela-bmwenda: https://github.com/andela-bmwenda .. _@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 Python
------ ------
* Code according to PEP8 Code according to PEP8, but with but with a maximum line length of 100.
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.
Javascript Javascript
@@ -29,12 +20,8 @@ Javascript
* Functions called from Django templates need to start with ``wger`` * 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 The coding style is automatically checked by GitHub actions after sending a
files you can run the following commands: pull request.
* 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)

View File

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

View File

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

View File

@@ -3,210 +3,63 @@
Development 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 Get the code
~~~~~~~~~~~~ ~~~~~~~~~~~~
::
The code is available on Github:: $ git clone https://github.com/wger-project/wger.git src
$ cd src
$ git clone https://github.com/wger-project/wger.git $ WGER_PATH=$(pwd)
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
Install Requirements Install Requirements
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
::
To install the Python requirements::
$ pip install -r requirements_devel.txt $ pip install -r requirements_devel.txt
$ npm install -g yarn sass
$ python setup.py develop
Install NodeJS and npm:: Install application
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 the npm modules:: This will download the required JS and CSS libraries and create a SQlite
database and populate it with data on the first run::
$ npm install
Install site $ wger create-settings \
~~~~~~~~~~~~ --settings-path $WGER_PATH/settings.py \
--database-path $WGER_PATH/database.sqlite
To install the server:: $ wger bootstrap \
--settings-path $WGER_PATH/settings.py \
$ 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 --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 Start the server
---------------- ----------------
To start the server:: After the first run you can just use django's development server::
$ python manage.py runserver $ 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 * **username**: admin
* **passsword**: admin * **password**: admin
You can start the application again with the django server with You can start the application again with the django server with
``python manage.py runserver``. ``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 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 running. They are all located under ``extras/docker`` if you want to build
them yourself. 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 Development
----------- -----------
@@ -12,10 +33,9 @@ Development
This image installs the application using virtualenv, uses a sqlite database This image installs the application using virtualenv, uses a sqlite database
and serves it with django's development server. and serves it with django's development server.
Get the image::
First build the image:: docker pull wger/devel
docker build -t wger/devel .
Run a container and start the application:: 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) source ~/venv/bin/activate
(in docker) python manage.py runserver 0.0.0.0:8000 (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 Then just open http://localhost:8000 and log in as: **admin**, password **admin**
http://localhost:8000).
Depending on what you intend to do with it, you might want to map a local folder As an alternative you might want to map a local folder to the container.
to the container. This is interesting if e.g. you want to keep the wger source This is interesting if e.g. you want to keep the wger source code on
code on your host machine and use docker only to serve it. Then you can do this:: your host machine and use docker only to serve it. Then do this::
docker run -ti \ docker run -ti \
--name wger.test1 \ --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 \ --volume /path/to/local/wger/:/home/wger/src \
wger/devel wger/devel
It will mount the local path *on top* of the folder in the container, basically It will mount the local path *on top* of the folder in the container. For this to
exchanging one for the other. Please note that for this to work you need to work you obviously need to manually checkout the code to ``/path/to/local/wger/``
manually checkout the code to ``/path/to/local/wger/`` and create a settings file and create a settings file as well.
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. This documentation is intended for developers and administrators of the software.
Installation and development Installation and administration
---------------------------- -------------------------------
.. toctree:: .. toctree::
:maxdepth: 2
install installation
commands
Development
-------------------------------
.. toctree::
tips_and_tricks
codingstyle
i18n i18n
Administration guide Administration guide
-------------------- --------------------
.. toctree:: .. toctree::
:maxdepth: 2
commands
settings settings
gym 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 didn't behave as you expected (in this case you can also open a ticket on the
issue tracker). 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, * **mailing list:** https://groups.google.com/group/wger / wger@googlegroups.com,
no registration needed 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 Sources
@@ -85,11 +90,3 @@ folders for more details.
.. include the authors file from the root folder .. include the authors file from the root folder
.. include:: ../AUTHORS.rst .. 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 @ECHO OFF
REM Command file for Sphinx documentation REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" ( if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build set SPHINXBUILD=sphinx-build
) )
set BUILDDIR=_build set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" ( if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
) )
if "%1" == "" goto help if "%1" == "" goto help
if "%1" == "help" ( if "%1" == "help" (
:help :help
echo.Please use `make ^<target^>` where ^<target^> is one of echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files echo. pickle to make pickle files
echo. json to make JSON files echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files echo. text to make text files
echo. man to make manual pages echo. man to make manual pages
echo. texinfo to make Texinfo files echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled echo. doctest to run all doctests embedded in the documentation if enabled
goto end goto end
) )
if "%1" == "clean" ( if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\* del /q /s %BUILDDIR%\*
goto end goto end
) )
%SPHINXBUILD% 2> nul %SPHINXBUILD% 2> nul
if errorlevel 9009 ( if errorlevel 9009 (
echo. echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH. echo.may add the Sphinx directory to PATH.
echo. echo.
echo.If you don't have Sphinx installed, grab it from echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/ echo.http://sphinx-doc.org/
exit /b 1 exit /b 1
) )
if "%1" == "html" ( if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html. echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end goto end
) )
if "%1" == "dirhtml" ( if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end goto end
) )
if "%1" == "singlehtml" ( if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end goto end
) )
if "%1" == "pickle" ( if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished; now you can process the pickle files. echo.Build finished; now you can process the pickle files.
goto end goto end
) )
if "%1" == "json" ( if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished; now you can process the JSON files. echo.Build finished; now you can process the JSON files.
goto end goto end
) )
if "%1" == "htmlhelp" ( if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished; now you can run HTML Help Workshop with the ^ echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp. .hhp project file in %BUILDDIR%/htmlhelp.
goto end goto end
) )
if "%1" == "qthelp" ( if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^ echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this: .qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wgerWorkoutManager.qhcp echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wgerWorkoutManager.qhcp
echo.To view the help file: echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wgerWorkoutManager.ghc echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wgerWorkoutManager.ghc
goto end goto end
) )
if "%1" == "devhelp" ( if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. echo.Build finished.
goto end goto end
) )
if "%1" == "epub" ( if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub. echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end goto end
) )
if "%1" == "latex" ( if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end goto end
) )
if "%1" == "latexpdf" ( if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex cd %BUILDDIR%/latex
make all-pdf make all-pdf
cd %BUILDDIR%/.. cd %BUILDDIR%/..
echo. echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex. echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end goto end
) )
if "%1" == "latexpdfja" ( if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex cd %BUILDDIR%/latex
make all-pdf-ja make all-pdf-ja
cd %BUILDDIR%/.. cd %BUILDDIR%/..
echo. echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex. echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end goto end
) )
if "%1" == "text" ( if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The text files are in %BUILDDIR%/text. echo.Build finished. The text files are in %BUILDDIR%/text.
goto end goto end
) )
if "%1" == "man" ( if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man. echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end goto end
) )
if "%1" == "texinfo" ( if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end goto end
) )
if "%1" == "gettext" ( if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale. echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end goto end
) )
if "%1" == "changes" ( if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.The overview file is in %BUILDDIR%/changes. echo.The overview file is in %BUILDDIR%/changes.
goto end goto end
) )
if "%1" == "linkcheck" ( if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Link check complete; look for any errors in the above output ^ echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt. or in %BUILDDIR%/linkcheck/output.txt.
goto end goto end
) )
if "%1" == "doctest" ( if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Testing of doctests in the sources finished, look at the ^ echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt. results in %BUILDDIR%/doctest/output.txt.
goto end goto end
) )
if "%1" == "xml" ( if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml. echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end goto end
) )
if "%1" == "pseudoxml" ( if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo. echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end goto end
) )
:end :end

View File

@@ -30,7 +30,7 @@ Configure apache to serve the application::
<VirtualHost *:80> <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 WSGIProcessGroup wger
WSGIScriptAlias / /home/wger/src/wger/wsgi.py WSGIScriptAlias / /home/wger/src/wger/wsgi.py
@@ -44,13 +44,13 @@ Configure apache to serve the application::
Require all granted Require all granted
</Directory> </Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log ErrorLog ${APACHE_LOG_DIR}/wger-error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined CustomLog ${APACHE_LOG_DIR}/wger-access.log combined
</VirtualHost> </VirtualHost>
Apache has a problem when uploading files that have non-ASCII characters, e.g. 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 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 LANG='en_US.UTF-8'
export LC_ALL='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 sudo service apache2 reload
Database Database
--------- --------
.. _prod_postgres:
postgreSQL postgreSQL
~~~~~~~~~~ ~~~~~~~~~~
Install the postgres server and create a database and a user:: 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 su - postgres
createdb wger createdb wger
psql wger -c "CREATE USER wger WITH PASSWORD 'wger'"; psql wger -c "CREATE USER wger WITH PASSWORD 'wger'";
@@ -94,7 +95,7 @@ Application
Make a virtualenv for python and activate it:: 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 source /home/wger/venv/bin/activate
Create folders to collect all static resources and save uploaded files. The 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 git clone https://github.com/wger-project/wger.git /home/wger/src
cd /home/wger/src cd /home/wger/src
npm install bower
pip install -r requirements.txt pip install -r requirements.txt
npm install -g yarn sass
python setup.py develop
pip install psycopg2 # Only if using postgres pip install psycopg2 # Only if using postgres
invoke create_settings \ wger create-settings \
--settings-path /home/wger/src/settings.py \ --settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite --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 Run the installation script, this will download some CSS and JS libraries and
load all initial data:: 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:: 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 Simple FunkLoad test
''' """
import unittest import unittest
from random import random from random import random
from funkload.FunkLoadTestCase import FunkLoadTestCase from funkload.FunkLoadTestCase import FunkLoadTestCase
class Simple(FunkLoadTestCase): class Simple(FunkLoadTestCase):
''' """
This test uses the configuration file Simple.conf. This test uses the configuration file Simple.conf.
''' """
def setUp(self): def setUp(self):
''' """
Setting up test. Setting up test.
''' """
self.server_url = self.conf_get('main', 'url') self.server_url = self.conf_get('main', 'url')
def test_simple(self): def test_simple(self):
# The description should be set in the configuration file # The description should be set in the configuration file
server_url = self.server_url server_url = self.server_url
# Exercises # Exercises
self.get(server_url + '/en/exercise/overview/', description='Get exercise overview') 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 + '/en/exercise/muscle/overview/', description='Get muscle overview')
self.get(server_url + '/de/exercise/79/view/', description='Get exercise page') 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 # 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 # Please consult the documentation for usage
# docker build --tag wger/apache . # docker build --tag wger/apache .
# docker run -ti --name wger.apache --publish 8000:80 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> RUN apt-get update \
EXPOSE 80 && apt-get install --no-install-recommends -y \
build-essential \
# Install dependencies python3-dev \
RUN apt-get install -y apache2 libapache2-mod-wsgi-py3 python3-pip \
python3-wheel \
# Configure apache git \
RUN a2dissite 000-default.conf && rm -rf /var/lib/apt/lists/*
ADD wger.conf /etc/apache2/sites-available/
RUN a2ensite wger
# Set up the application # 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 USER wger
RUN git clone https://github.com/wger-project/wger.git /home/wger/src
WORKDIR /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 \ RUN . /home/wger/venv/bin/activate \
&& pip install --upgrade pip \ && pip install --upgrade pip \
&& pip install -r requirements.txt \ && pip install wheel \
&& invoke create_settings \ && pip install --no-cache /wheels/* \
&& python setup.py develop \
&& wger create-settings \
--settings-path /home/wger/src/settings.py \ --settings-path /home/wger/src/settings.py \
--database-path /home/wger/db/database.sqlite \ --database-path /home/wger/db/database.sqlite \
&& invoke bootstrap_wger \ && wger bootstrap \
--settings-path /home/wger/src/settings.py \ --settings-path /home/wger/src/settings.py \
--no-start-server --no-start-server
# Change permissions of some files and folders so the apache process # Change permissions of some files and folders so the apache process
# can access them. # can access them.
RUN chmod o+w -R ~/db/ \ RUN mkdir -p ~/static/CACHE ~/media \
&& . /home/wger/venv/bin/activate \ && ln -s /home/wger/static/CACHE /home/wger/src/CACHE \
&& mkdir ~/static \ && chmod g+w /home/wger/static/CACHE \
&& mkdir ~/media \
&& chmod o+w ~/media \
&& sed -i "/^MEDIA_ROOT/c\MEDIA_ROOT='\/home\/wger\/media'" settings.py \ && 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
&& echo STATIC_ROOT=\'/home/wger/static\' >> settings.py \
&& python manage.py collectstatic --noinput
USER root 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"] ENTRYPOINT ["/home/wger/entrypoint.sh"]
CMD ["-D", "FOREGROUND"]

View File

@@ -18,7 +18,25 @@ play around. To start it:
```docker run -ti --name wger.apache --publish 8000:80 wger/apache``` ```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 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 report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway. file a bug anyway.
* twitter: https://twitter.com/wger_de * gitter: <https://gitter.im/wger-project/wger>
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed * issue tracker: <https://github.com/wger-project/wger/issues>
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger * twitter: <https://twitter.com/wger_project>
* issue tracker: https://github.com/wger-project/wger/issues * 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: All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger * Main repository: <https://github.com/wger-project/wger>
* Mirror: https://bitbucket.org/rolandgeider/wger
Licence 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> <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 WSGIProcessGroup wger
WSGIScriptAlias / /home/wger/src/wger/wsgi.py WSGIScriptAlias / /home/wger/src/wger/wsgi.py
WSGIPassAuthorization On
Alias /static/ /home/wger/static/ Alias /static/ /home/wger/static/
<Directory /home/wger/static> <Directory /home/wger/static>
Require all granted Require all granted
Header set Cache-Control "max-age=604800, public"
</Directory> </Directory>
Alias /media/ /home/wger/media/ Alias /media/ /home/wger/media/
<Directory /home/wger//media> <Directory /home/wger/media>
Require all granted Require all granted
Header set Cache-Control "max-age=604800, public"
</Directory> </Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log ErrorLog ${APACHE_LOG_DIR}/wger-error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined CustomLog ${APACHE_LOG_DIR}/wger-access.log combined
</VirtualHost> </VirtualHost>
ServerSignature Off
ServerTokens Prod

View File

@@ -8,17 +8,34 @@
# docker build --tag wger/base . # 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 # Install dependencies
RUN apt-get update;\ ENV DEBIAN_FRONTEND=noninteractive
apt-get install -y nodejs nodejs-legacy npm git \ RUN apt-get update \
python-virtualenv python3-dev \ && apt-get install --no-install-recommends -y \
libjpeg8-dev zlib1g-dev libwebp-dev \ git \
sudo 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 # Add wger user
RUN adduser wger --disabled-password --gecos "" 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 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. 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 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 report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway. file a bug anyway.
* twitter: https://twitter.com/wger_de * gitter: <https://gitter.im/wger-project/wger>
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed * issue tracker: <https://github.com/wger-project/wger/issues>
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger * twitter: <https://twitter.com/wger_project>
* issue tracker: https://github.com/wger-project/wger/issues * 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: All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger * Main repository: <https://github.com/wger-project/wger>
* Mirror: https://bitbucket.org/rolandgeider/wger
Licence 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 # Docker image for wger development
# #
# Please consult the documentation for usage # Please consult the README 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
# #
# 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 EXPOSE 8000
# Install dependencies
RUN apt-get install -y vim tmux sqlite3
# Set up the application # Set up the application
USER wger
RUN git clone https://github.com/wger-project/wger.git /home/wger/src
WORKDIR /home/wger/src WORKDIR /home/wger/src
RUN virtualenv --python python3 /home/wger/venv COPY --chown=wger:wger . /home/wger/src
RUN . /home/wger/venv/bin/activate \ COPY --from=builder /wheels /wheels
&& pip install --upgrade pip \ COPY ${DOCKER_DIR}/settings.py /home/wger/src
&& pip install -r requirements_devel.txt \ COPY ${DOCKER_DIR}/settings.py /tmp/
&& invoke create_settings \ COPY ${DOCKER_DIR}/entrypoint.sh /home/wger/entrypoint.sh
--settings-path /home/wger/src/settings.py \ RUN chmod +x /home/wger/entrypoint.sh
--database-path /home/wger/db/database.sqlite \ RUN pip3 install --no-cache /wheels/* \
&& invoke bootstrap_wger \ && pip3 install psycopg2-binary \
--settings-path /home/wger/src/settings.py \ && pip3 install django-redis \
--no-start-server && python3 setup.py develop
# Install node modules for JS linting and download the exercise images RUN chown -R wger:wger .
#
# 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
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 Thank you for downloading wger Workout Manager. wger (ˈɡɐ) is a free, open
source web application that manages your exercises and personal workouts, weight 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 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 different administrative roles (trainer, manager, etc.). It offers a REST API
as well, for easy integration with other projects and tools. 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 This docker image is meant to provide a quick development environment using
development server using a sqlite database. It can be used to quickly setup a django's development server and an sqlite database from your current code
development instance (vim and tmux are already installed): 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 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 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 report liberally. If you're not sure if something is a bug or not, feel free to
file a bug anyway. file a bug anyway.
* twitter: https://twitter.com/wger_de * gitter: <https://gitter.im/wger-project/wger>
* mailing list: https://groups.google.com/group/wger / wger@googlegroups.com, no registration needed * issue tracker: <https://github.com/wger-project/wger/issues>
* IRC: channel #wger on freenode.net, webchat: http://webchat.freenode.net/?channels=wger * twitter: <https://twitter.com/wger_project>
* issue tracker: https://github.com/wger-project/wger/issues * 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: All the code and the content is freely available:
* Main repository: https://github.com/wger-project/wger * Main repository: <https://github.com/wger-project/wger>
* Mirror: https://bitbucket.org/rolandgeider/wger
Licence ## Licence
-------
The application is licenced under the Affero GNU General Public License 3 or The application is licenced under the Affero GNU General Public License 3 or
later (AGPL 3+). 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 -*- # -*- coding: utf-8 -*-
# flake8: noqa
# This file is part of wger Workout Manager. # This file is part of wger Workout Manager.
# #
@@ -80,7 +81,7 @@ user_parser.add_argument('--country',
action='store', action='store',
default='germany', default='germany',
help='What country the generated users should belong to. Default: Germany', help='What country the generated users should belong to. Default: Germany',
choices=['germany', 'ukraine', 'spain']) choices=['germany', 'ukraine', 'spain', 'usa'])
# Workout options # Workout options
workouts_parser = subparsers.add_parser('workouts', help='Create workouts') 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 per plan
total_meals = 4 total_meals = 4
for user in userlist: for user in userlist:
print(' - generating for {0}'.format(user.username)) 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 # 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 Simple script that filters the output of django's dumpdata command into more
manageable chunks. manageable chunks.
Create the data.json e.g. with: Create the data.json e.g. with:
python ../../manage.py dumpdata --indent 4 --natural-foreign > data.json python ../../manage.py dumpdata --indent 4 --natural-foreign > data.json
''' """
import json import json
def filter_dump(data, model_list, filename): def filter_dump(data, model_list, filename):
''' """
Helper function Helper function
''' """
filter_data = [i for i in data if i['model'] in model_list] filter_data = [i for i in data if i['model'] in model_list]
with open(filename, 'w') as outfile: if filter_data:
json.dump(filter_data, outfile, indent=4) with open(filename, 'w') as outfile:
json.dump(filter_data, outfile, indent=4)
# This is a full dump of the DB # This is a full dump of the DB
fixture = open('data.json') fixture = open('data.json')
@@ -44,6 +46,7 @@ fixture.close()
filter_dump(data, ('nutrition.ingredient',), 'ingredients.json') filter_dump(data, ('nutrition.ingredient',), 'ingredients.json')
filter_dump(data, ('nutrition.weightunit',), 'weight_units.json') filter_dump(data, ('nutrition.weightunit',), 'weight_units.json')
filter_dump(data, ('nutrition.ingredientweightunit',), 'ingredient_units.json') filter_dump(data, ('nutrition.ingredientweightunit',), 'ingredient_units.json')
filter_dump(data, ('nutrition.logitem',), 'nutrition_diary.json')
# #
# Exercises # 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 #!/usr/bin/env python
# Standard Library
import sys import sys
# Django
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
from tasks import ( # wger
setup_django_environment, from wger.tasks import (
get_user_config_path get_user_config_path,
setup_django_environment
) )
if __name__ == "__main__": if __name__ == "__main__":
# If user passed the settings flag ignore the default wger settings # If user passed the settings flag ignore the default wger settings

View File

@@ -1,13 +1,10 @@
{ {
"name": "wger", "name": "wger",
"version": "1.8.0", "version": "2.0.dev1",
"description": "Self hosted FLOSS fitness/workout and weight tracker", "description": "Self hosted FLOSS fitness/workout and weight tracker",
"directories": { "directories": {
"doc": "docs" "doc": "docs"
}, },
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/wger-project/wger/wger.git" "url": "git+https://github.com/wger-project/wger/wger.git"
@@ -18,13 +15,20 @@
"url": "https://github.com/wger-project/wger/issues" "url": "https://github.com/wger-project/wger/issues"
}, },
"homepage": "https://github.com/wger-project/wger", "homepage": "https://github.com/wger-project/wger",
"devDependencies": { "dependencies": {
"eslint": "^3.3.1", "yarn": "^1.22.5",
"eslint-config-airbnb-base": "^5.0.2", "Sortable": "RubaXa/Sortable#1.10.2",
"eslint-plugin-import": "^1.13.0", "bootstrap": "twbs/bootstrap#4.x",
"eslint-plugin-jsx-a11y": "^2.1.0", "components-font-awesome": "components/font-awesome#5.14.0",
"eslint-plugin-react": "^6.1.2", "d3": "mbostock-bower/d3-bower#>=5",
"gulp": "^3.9.1", "datatables": "DataTables/DataTables#1.10.x",
"gulp-eslint": "^3.0.1" "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 # Requirements for wger for production
# #
bleach # Building/installing
wheel
# Application
bleach~=3.1
django-activity-stream django-activity-stream
django-bootstrap-breadcrumbs django-bootstrap-breadcrumbs~=0.9
django-bower django-formtools~=2.2
django-formtools>=1.0,<1.1 django-recaptcha==2.0.6
django-recaptcha Django~=3.1
django-sortedm2m django-crispy-forms~=1.9
Django>=1.9,<1.10 django_compressor~=2.4
django_compressor django_extensions~=3.0
django_mobile django-sortedm2m~=3.0
easy-thumbnails django-storages~=1.9
icalendar easy-thumbnails~=2.7
invoke>=0.14,<0.15 icalendar==4.0.6
pillow invoke~=1.4
pillow~=7.2
python-mimeparse python-mimeparse
reportlab>=3.3,<3.4 reportlab==3.5.48
matplotlib>=3.1
requests requests
setuptools>=18.5
sphinx sphinx
# REST API # AWS
django-cors-headers #boto3
django-filter
django-tastypie>=0.13,<0.14 # Production
djangorestframework>=3.2,<3.3 #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 -r requirements.txt
# Development packages # Development packages
pep8 coverage
django-debug-toolbar django-debug-toolbar
coverage tblib
transifex-client
isort

View File

@@ -1,7 +1,69 @@
[bdist_wheel] [bdist_wheel]
universal = 1 universal = 1
[pep8] [isort]
exclude = urls.py,tasks.py,*migrations*,*bower_components* sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
max-line-length = 100 skip: extras,build,dist,node_modules,migrations,docs,settings.py,apps.py
ignore = W503
# 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. :license: GNU GPL, see LICENSE for more details.
""" """
# Third Party
from setuptools import ( from setuptools import (
setup, find_packages,
find_packages setup
) )
# wger
from wger import get_version from wger import get_version
@@ -24,6 +27,7 @@ setup(
name='wger', name='wger',
description='FLOSS workout, fitness and weight manager/tracker written with Django', description='FLOSS workout, fitness and weight manager/tracker written with Django',
long_description=long_description, long_description=long_description,
long_description_content_type='text/x-rst',
version=get_version(), version=get_version(),
url='https://github.com/wger-project', url='https://github.com/wger-project',
author='Roland Geider', author='Roland Geider',
@@ -39,13 +43,13 @@ setup(
'Framework :: Django', 'Framework :: Django',
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
], ],
install_requires=install_requires,
nstall_requires=install_requires,
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
'wger = wger.__main__:main', 'wger = wger.__main__:main',

View File

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

View File

@@ -14,20 +14,27 @@
# #
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# Standard Library
import os import os
import sys import sys
# Third Party
from invoke import run from invoke import run
'''
"""
This simple wrapper script is used as a console entry point in the packaged 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 version of the application. It simply redirects all arguments to the invoke
command, which does all the work. command, which does all the work.
''' """
invoke_cmd = 'invoke ' invoke_cmd = 'invoke '
def main(): 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:] args = sys.argv[1:]
if len(args): if len(args):
run(invoke_cmd + ' '.join(args), pty=True) 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/>. # along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# wger
from wger import get_version from wger import get_version
VERSION = get_version() VERSION = get_version()
default_app_config = 'wger.config.apps.ConfigConfig' 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 # You should have received a copy of the GNU Affero General Public License
# Django
from django.apps import AppConfig from django.apps import AppConfig

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# flake8: noqa
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
@@ -16,7 +17,9 @@ class Migration(migrations.Migration):
name='GymConfig', name='GymConfig',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('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={ options={
}, },
@@ -28,8 +31,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('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')])), ('item', models.CharField(max_length=2, editable=False, choices=[(b'1', 'Exercises'), (b'2', 'Ingredients')])),
('show', models.BooleanField(default=1)), ('show', models.BooleanField(default=1)),
('language', models.ForeignKey(related_name='language_source', 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')), ('language_target', models.ForeignKey(related_name='language_target', editable=False, to='core.Language', on_delete=models.CASCADE)),
], ],
options={ options={
'ordering': ['item', 'language_target'], '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 # 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/>. # along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Standard Library
import logging import logging
from django.db import models # Django
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache from django.core.cache import cache
from wger.core.models import Language, UserProfile from django.db import models
from wger.gym.helpers import is_any_gym_admin from django.utils.translation import ugettext_lazy as _
from wger.gym.models import Gym, GymUserConfig
from wger.utils.cache import delete_template_fragment_cache # wger
from wger.utils.cache import cache_mapper 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__) logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class LanguageConfig(models.Model): class LanguageConfig(models.Model):
''' """
Configuration for languages Configuration for languages
Allows to specify what exercises and ingredients are shown for each language Allows to specify what exercises and ingredients are shown for each language
''' """
SHOW_ITEM_EXERCISES = '1' SHOW_ITEM_EXERCISES = '1'
SHOW_ITEM_INGREDIENTS = '2' SHOW_ITEM_INGREDIENTS = '2'
SHOW_ITEM_LIST = ( SHOW_ITEM_LIST = (
@@ -48,31 +57,33 @@ class LanguageConfig(models.Model):
language = models.ForeignKey(Language, language = models.ForeignKey(Language,
related_name='language_source', related_name='language_source',
editable=False) editable=False,
on_delete=models.CASCADE)
language_target = models.ForeignKey(Language, language_target = models.ForeignKey(Language,
related_name='language_target', related_name='language_target',
editable=False) editable=False,
on_delete=models.CASCADE)
item = models.CharField(max_length=2, item = models.CharField(max_length=2,
choices=SHOW_ITEM_LIST, choices=SHOW_ITEM_LIST,
editable=False) editable=False)
show = models.BooleanField(default=1) show = models.BooleanField(default=1)
class Meta: class Meta:
''' """
Set some other properties Set some other properties
''' """
ordering = ["item", "language_target", ] ordering = ["item", "language_target", ]
def __str__(self): def __str__(self):
''' """
Return a more human-readable representation Return a more human-readable representation
''' """
return u"Config for language {0}".format(self.language) return u"Config for language {0}".format(self.language)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
''' """
Reset all cached infos Reset all cached infos
''' """
super(LanguageConfig, self).save(*args, **kwargs) super(LanguageConfig, self).save(*args, **kwargs)
@@ -84,9 +95,9 @@ class LanguageConfig(models.Model):
delete_template_fragment_cache('exercise-overview', self.language_id) delete_template_fragment_cache('exercise-overview', self.language_id)
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
''' """
Reset all cached infos Reset all cached infos
''' """
# Cached objects # Cached objects
cache.delete(cache_mapper.get_language_config_key(self.language, self.item)) 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) super(LanguageConfig, self).delete(*args, **kwargs)
@python_2_unicode_compatible
class GymConfig(models.Model): class GymConfig(models.Model):
''' """
System wide configuration for gyms System wide configuration for gyms
At the moment this only allows to set one gym as the default At the moment this only allows to set one gym as the default
TODO: close registration (users can only become members thorough an admin) TODO: close registration (users can only become members thorough an admin)
''' """
default_gym = models.ForeignKey(Gym, default_gym = models.ForeignKey(Gym,
verbose_name=_('Default gym'), verbose_name=_('Default gym'),
@@ -114,21 +124,22 @@ class GymConfig(models.Model):
'gym and update all existing users without a ' 'gym and update all existing users without a '
'gym.'), 'gym.'),
null=True, null=True,
blank=True) blank=True,
''' on_delete=models.CASCADE)
"""
Default gym for the wger installation Default gym for the wger installation
''' """
def __str__(self): def __str__(self):
''' """
Return a more human-readable representation Return a more human-readable representation
''' """
return u"Default gym {0}".format(self.default_gym) return u"Default gym {0}".format(self.default_gym)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
''' """
Perform additional tasks Perform additional tasks
''' """
if self.default_gym: if self.default_gym:
# All users that have no gym set in the profile are edited # 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 # You should have received a copy of the GNU Affero General Public License
# Django
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
# wger
from wger.config.models import LanguageConfig from wger.config.models import LanguageConfig
from wger.core.models import Language from wger.core.models import Language
@receiver(post_save, sender=Language) @receiver(post_save, sender=Language)
def init_language_config(sender, instance, created, **kwargs): def init_language_config(sender, instance, created, **kwargs):
''' """
Creates language config entries when new languages are created Creates language config entries when new languages are created
(all combinations of all languages) (all combinations of all languages)
''' """
for language_source in Language.objects.all(): for language_source in Language.objects.all():
for language_target in Language.objects.all(): for language_target in Language.objects.all():
if not LanguageConfig.objects.filter(language=language_source)\ if not LanguageConfig.objects.filter(language=language_source)\

View File

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

View File

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

View File

@@ -15,16 +15,18 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # 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.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 Test case for showing gym name on application header
''' """
def check_header(self, gym=None): def check_header(self, gym=None):
@@ -32,9 +34,9 @@ class GymNameHeaderTestCase(WorkoutManagerTestCase):
self.assertEqual(response.context['custom_header'], gym) self.assertEqual(response.context['custom_header'], gym)
def test_custom_header_gym_members(self): def test_custom_header_gym_members(self):
''' """
Test the custom header for gym members Test the custom header for gym members
''' """
# Gym 1, custom header activated # Gym 1, custom header activated
gym = Gym.objects.get(pk=1) gym = Gym.objects.get(pk=1)
@@ -60,7 +62,7 @@ class GymNameHeaderTestCase(WorkoutManagerTestCase):
self.check_header(gym=None) self.check_header(gym=None)
def test_custom_header_anonymous_user(self): def test_custom_header_anonymous_user(self):
''' """
Test the custom header for logged out users Test the custom header for logged out users
''' """
self.check_header(gym=None) self.check_header(gym=None)

View File

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

View File

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

View File

@@ -15,25 +15,32 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # 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 # wger
from wger.config.views import gym_config from wger.config.views import (
gym_config,
language_config
)
# sub patterns for language configs # sub patterns for language configs
patterns_language_config = [ patterns_language_config = [
url(r'^(?P<pk>\d+)/edit', url(r'^(?P<pk>\d+)/edit',
language_config.LanguageConfigUpdateView.as_view(), language_config.LanguageConfigUpdateView.as_view(),
name='edit'), name='edit'),
] ]
# sub patterns for default gym # sub patterns for default gym
patterns_gym_config = [ patterns_gym_config = [
url(r'^edit$', url(r'^edit$',
gym_config.GymConfigUpdateView.as_view(), gym_config.GymConfigUpdateView.as_view(),
name='edit'), name='edit'),
] ]
@@ -41,6 +48,6 @@ patterns_gym_config = [
# Actual patterns # Actual patterns
# #
urlpatterns = [ urlpatterns = [
url(r'^language-config/', include(patterns_language_config, namespace="language_config")), url(r'^language-config/', include((patterns_language_config, 'language_config'), namespace="language_config")),
url(r'^gym-config/', include(patterns_gym_config, namespace="gym_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 # You should have received a copy of the GNU Affero General Public License
# Standard Library
import logging import logging
from django.core.urlresolvers import reverse, reverse_lazy # Django
from django.utils.translation import ugettext as _ from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy
from django.views.generic import UpdateView from django.views.generic import UpdateView
# wger
from wger.config.models import GymConfig from wger.config.models import GymConfig
from wger.utils.generic_views import WgerFormMixin from wger.utils.generic_views import WgerFormMixin
@@ -28,22 +31,17 @@ logger = logging.getLogger(__name__)
class GymConfigUpdateView(WgerFormMixin, UpdateView): class GymConfigUpdateView(WgerFormMixin, UpdateView):
''' """
Generic view to edit the gym config table Generic view to edit the gym config table
''' """
model = GymConfig model = GymConfig
fields = '__all__' fields = '__all__'
permission_required = 'config.change_gymconfig' permission_required = 'config.change_gymconfig'
success_url = reverse_lazy('gym:gym:list') success_url = reverse_lazy('gym:gym:list')
title = ugettext_lazy('Edit')
def get_object(self): def get_object(self):
''' """
Return the only gym config object Return the only gym config object
''' """
return GymConfig.objects.get(pk=1) 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 # You should have received a copy of the GNU Affero General Public License
# Standard Library
import logging import logging
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin # Django
from django.core.urlresolvers import reverse, reverse_lazy from django.contrib.auth.mixins import (
from django.utils.translation import ugettext as _ LoginRequiredMixin,
PermissionRequiredMixin
)
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy
from django.views.generic import UpdateView from django.views.generic import UpdateView
# wger
from wger.config.models import LanguageConfig from wger.config.models import LanguageConfig
from wger.utils.generic_views import WgerFormMixin from wger.utils.generic_views import WgerFormMixin
@@ -32,23 +38,16 @@ class LanguageConfigUpdateView(WgerFormMixin,
LoginRequiredMixin, LoginRequiredMixin,
PermissionRequiredMixin, PermissionRequiredMixin,
UpdateView): UpdateView):
''' """
Generic view to edit a language config Generic view to edit a language config
''' """
model = LanguageConfig model = LanguageConfig
fields = ['show'] fields = ['show']
permission_required = 'config.change_languageconfig' permission_required = 'config.change_languageconfig'
title = ugettext_lazy('Edit')
def get_success_url(self): def get_success_url(self):
''' """
Return to the language page Return to the language page
''' """
return reverse_lazy('core:language:view', kwargs={'pk': self.object.language_id}) 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/>. # along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# wger
from wger import get_version from wger import get_version
VERSION = get_version() VERSION = get_version()
default_app_config = 'wger.core.apps.CoreConfig' 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 # 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/>. # along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Third Party
from rest_framework import serializers from rest_framework import serializers
# wger
from wger.core.models import ( from wger.core.models import (
UserProfile,
Language,
DaysOfWeek, DaysOfWeek,
Language,
License, License,
RepetitionUnit, RepetitionUnit,
WeightUnit) UserProfile,
WeightUnit
)
class UserprofileSerializer(serializers.ModelSerializer): class UserprofileSerializer(serializers.ModelSerializer):
''' """
Workout session serializer Workout session serializer
''' """
class Meta: class Meta:
model = UserProfile model = UserProfile
fields = '__all__'
class UsernameSerializer(serializers.Serializer): class UsernameSerializer(serializers.Serializer):
''' """
Serializer to extract the username Serializer to extract the username
''' """
username = serializers.CharField() username = serializers.CharField()
class LanguageSerializer(serializers.ModelSerializer): class LanguageSerializer(serializers.ModelSerializer):
''' """
Language serializer Language serializer
''' """
class Meta: class Meta:
model = Language model = Language
fields = '__all__'
class DaysOfWeekSerializer(serializers.ModelSerializer): class DaysOfWeekSerializer(serializers.ModelSerializer):
''' """
DaysOfWeek serializer DaysOfWeek serializer
''' """
class Meta: class Meta:
model = DaysOfWeek model = DaysOfWeek
fields = '__all__'
class LicenseSerializer(serializers.ModelSerializer): class LicenseSerializer(serializers.ModelSerializer):
''' """
License serializer License serializer
''' """
class Meta: class Meta:
model = License model = License
fields = '__all__'
class RepetitionUnitSerializer(serializers.ModelSerializer): class RepetitionUnitSerializer(serializers.ModelSerializer):
''' """
Repetition unit serializer Repetition unit serializer
''' """
class Meta: class Meta:
model = RepetitionUnit model = RepetitionUnit
fields = '__all__'
class WeightUnitSerializer(serializers.ModelSerializer): class WeightUnitSerializer(serializers.ModelSerializer):
''' """
Weight unit serializer Weight unit serializer
''' """
class Meta: class Meta:
model = WeightUnit model = WeightUnit
fields = '__all__'

View File

@@ -15,109 +15,117 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with Workout Manager. If not, see <http://www.gnu.org/licenses/>.
# Django
from django.contrib.auth.models import User 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 ( # Third Party
UserProfile, from rest_framework import viewsets
Language, from rest_framework.decorators import action
DaysOfWeek, from rest_framework.response import Response
License,
RepetitionUnit, # wger
WeightUnit)
from wger.core.api.serializers import ( from wger.core.api.serializers import (
UsernameSerializer,
LanguageSerializer,
DaysOfWeekSerializer, DaysOfWeekSerializer,
LanguageSerializer,
LicenseSerializer, LicenseSerializer,
RepetitionUnitSerializer, RepetitionUnitSerializer,
UsernameSerializer,
UserprofileSerializer,
WeightUnitSerializer WeightUnitSerializer
) )
from wger.core.api.serializers import UserprofileSerializer from wger.core.models import (
from wger.utils.permissions import UpdateOnlyPermission, WgerPermission DaysOfWeek,
Language,
License,
RepetitionUnit,
UserProfile,
WeightUnit
)
from wger.utils.permissions import (
UpdateOnlyPermission,
WgerPermission
)
class UserProfileViewSet(viewsets.ModelViewSet): class UserProfileViewSet(viewsets.ModelViewSet):
''' """
API endpoint for workout objects API endpoint for workout objects
''' """
is_private = True is_private = True
serializer_class = UserprofileSerializer serializer_class = UserprofileSerializer
permission_classes = (WgerPermission, UpdateOnlyPermission) permission_classes = (WgerPermission, UpdateOnlyPermission)
ordering_fields = '__all__' ordering_fields = '__all__'
def get_queryset(self): def get_queryset(self):
''' """
Only allow access to appropriate objects Only allow access to appropriate objects
''' """
return UserProfile.objects.filter(user=self.request.user) return UserProfile.objects.filter(user=self.request.user)
def get_owner_objects(self): def get_owner_objects(self):
''' """
Return objects to check for ownership permission Return objects to check for ownership permission
''' """
return [(User, 'user')] return [(User, 'user')]
@detail_route() @action(detail=True)
def username(self, request, pk): def username(self, request, pk):
''' """
Return the username Return the username
''' """
user = self.get_object().user user = self.get_object().user
return Response(UsernameSerializer(user).data) return Response(UsernameSerializer(user).data)
class LanguageViewSet(viewsets.ReadOnlyModelViewSet): class LanguageViewSet(viewsets.ReadOnlyModelViewSet):
''' """
API endpoint for workout objects API endpoint for workout objects
''' """
queryset = Language.objects.all() queryset = Language.objects.all()
serializer_class = LanguageSerializer serializer_class = LanguageSerializer
ordering_fields = '__all__' ordering_fields = '__all__'
filter_fields = ('full_name', filterset_fields = ('full_name',
'short_name') 'short_name')
class DaysOfWeekViewSet(viewsets.ReadOnlyModelViewSet): class DaysOfWeekViewSet(viewsets.ReadOnlyModelViewSet):
''' """
API endpoint for workout objects API endpoint for workout objects
''' """
queryset = DaysOfWeek.objects.all() queryset = DaysOfWeek.objects.all()
serializer_class = DaysOfWeekSerializer serializer_class = DaysOfWeekSerializer
ordering_fields = '__all__' ordering_fields = '__all__'
filter_fields = ('day_of_week', ) filterset_fields = ('day_of_week', )
class LicenseViewSet(viewsets.ReadOnlyModelViewSet): class LicenseViewSet(viewsets.ReadOnlyModelViewSet):
''' """
API endpoint for workout objects API endpoint for workout objects
''' """
queryset = License.objects.all() queryset = License.objects.all()
serializer_class = LicenseSerializer serializer_class = LicenseSerializer
ordering_fields = '__all__' ordering_fields = '__all__'
filter_fields = ('full_name', filterset_fields = ('full_name',
'short_name', 'short_name',
'url') 'url')
class RepetitionUnitViewSet(viewsets.ReadOnlyModelViewSet): class RepetitionUnitViewSet(viewsets.ReadOnlyModelViewSet):
''' """
API endpoint for repetition units objects API endpoint for repetition units objects
''' """
queryset = RepetitionUnit.objects.all() queryset = RepetitionUnit.objects.all()
serializer_class = RepetitionUnitSerializer serializer_class = RepetitionUnitSerializer
ordering_fields = '__all__' ordering_fields = '__all__'
filter_fields = ('name', ) filterset_fields = ('name', )
class WeightUnitViewSet(viewsets.ReadOnlyModelViewSet): class WeightUnitViewSet(viewsets.ReadOnlyModelViewSet):
''' """
API endpoint for weight units objects API endpoint for weight units objects
''' """
queryset = WeightUnit.objects.all() queryset = WeightUnit.objects.all()
serializer_class = WeightUnitSerializer serializer_class = WeightUnitSerializer
ordering_fields = '__all__' 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 # You should have received a copy of the GNU Affero General Public License
# Django
from django.apps import AppConfig, apps 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 # You should have received a copy of the GNU Affero General Public License
# Standard Library
import datetime
import logging import logging
import random import random
import datetime
import uuid import uuid
from django.contrib.auth.models import User # Django
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from wger.weight.models import WeightEntry # wger
from wger.exercises.models import Exercise
from wger.core.models import DaysOfWeek from wger.core.models import DaysOfWeek
from wger.exercises.models import Exercise
from wger.manager.models import ( from wger.manager.models import (
Workout,
Day, Day,
Schedule,
ScheduleStep,
Set, Set,
Setting, Setting,
WorkoutLog, Workout,
Schedule, WorkoutLog
ScheduleStep
) )
from wger.nutrition.models import ( from wger.nutrition.models import (
NutritionPlan, Ingredient,
IngredientWeightUnit,
Meal, Meal,
MealItem, MealItem,
Ingredient, NutritionPlan
IngredientWeightUnit
) )
from wger.utils.language import load_language from wger.utils.language import load_language
from wger.weight.models import WeightEntry
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def create_temporary_user(): def create_temporary_user():
''' """
Creates a temporary user Creates a temporary user
''' """
username = uuid.uuid4().hex[:-2] username = uuid.uuid4().hex[:-2]
password = uuid.uuid4().hex[:-2] password = uuid.uuid4().hex[:-2]
email = '' email = ''
@@ -68,9 +71,9 @@ def create_temporary_user():
def create_demo_entries(user): def create_demo_entries(user):
''' """
Creates some demo data for temporary users Creates some demo data for temporary users
''' """
# (this is a bit ugly and long...) # (this is a bit ugly and long...)
language = load_language() language = load_language()

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,19 +1,19 @@
[ [
{ {
"pk": 1, "pk": 1,
"model": "core.license", "model": "core.license",
"fields": { "fields": {
"url": "", "url": "",
"full_name": "A cool and free license - Germany", "full_name": "A cool and free license - Germany",
"short_name": "ACAFL - DE" "short_name": "ACAFL - DE"
} }
}, },
{ {
"pk": 2, "pk": 2,
"model": "core.license", "model": "core.license",
"fields": { "fields": {
"url": "https://another-cool-license.org/acl-2.1", "url": "https://another-cool-license.org/acl-2.1",
"full_name": "Another cool license 2.1", "full_name": "Another cool license 2.1",
"short_name": "ACL 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", "model": "auth.user",
"fields": { "fields": {
"username": "admin", "username": "admin",
@@ -34,12 +34,12 @@
} }
}, },
{ {
"pk": 1, "pk": 1,
"model": "core.userprofile", "model": "core.userprofile",
"fields": { "fields": {
"is_temporary": false, "is_temporary": false,
"show_comments": false, "show_comments": false,
"show_english_ingredients": false, "show_english_ingredients": false,
"user": 1, "user": 1,
"gym": 1 "gym": 1
} }

View File

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