Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Oliver Walters 2021-06-17 00:34:29 +10:00
commit 4703fdf1b3
20 changed files with 145 additions and 78 deletions

5
.gitignore vendored
View File

@ -61,4 +61,7 @@ secret_key.txt
# Coverage reports
.coverage
htmlcov/
htmlcov/
# Development files
dev/

View File

@ -191,7 +191,7 @@ STATIC_URL = '/static/'
STATIC_ROOT = os.path.abspath(
get_setting(
'INVENTREE_STATIC_ROOT',
CONFIG.get('static_root', '/home/inventree/static')
CONFIG.get('static_root', '/home/inventree/data/static')
)
)

View File

@ -37,6 +37,7 @@ from django.conf.urls.static import static
from django.views.generic.base import RedirectView
from rest_framework.documentation import include_docs_urls
from .views import auth_request
from .views import IndexView, SearchView, DatabaseStatsView
from .views import SettingsView, EditUserView, SetPasswordView
from .views import CurrencySettingsView, CurrencyRefreshView
@ -155,24 +156,28 @@ urlpatterns = [
url(r'^search/', SearchView.as_view(), name='search'),
url(r'^stats/', DatabaseStatsView.as_view(), name='stats'),
url(r'^auth/?', auth_request),
url(r'^api/', include(apipatterns)),
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
url(r'^markdownx/', include('markdownx.urls')),
]
# Static file access
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
# Server running in "DEBUG" mode?
if settings.DEBUG:
# Static file access
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
# Media file access
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# Media file access
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# Debug toolbar access (if in DEBUG mode)
if settings.DEBUG and 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns = [
path('__debug/', include(debug_toolbar.urls)),
] + urlpatterns
# Debug toolbar access (only allowed in DEBUG mode)
if 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns = [
path('__debug/', include(debug_toolbar.urls)),
] + urlpatterns
# Send any unknown URLs to the parts page
urlpatterns += [url(r'^.*$', RedirectView.as_view(url='/index/', permanent=False), name='index')]

View File

@ -8,7 +8,7 @@ import re
import common.models
INVENTREE_SW_VERSION = "0.2.3 pre"
INVENTREE_SW_VERSION = "0.2.4 pre"
"""
Increment thi API version number whenever there is a significant change to the API that any clients need to know about

View File

@ -10,7 +10,7 @@ from __future__ import unicode_literals
from django.utils.translation import gettext_lazy as _
from django.template.loader import render_to_string
from django.http import JsonResponse, HttpResponseRedirect
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.urls import reverse_lazy
from django.conf import settings
@ -36,6 +36,19 @@ from .helpers import str2bool
from rest_framework import views
def auth_request(request):
"""
Simple 'auth' endpoint used to determine if the user is authenticated.
Useful for (for example) redirecting authentication requests through
django's permission framework.
"""
if request.user.is_authenticated:
return HttpResponse(status=200)
else:
return HttpResponse(status=403)
class TreeSerializer(views.APIView):
""" JSON View for serializing a Tree object.

View File

@ -129,9 +129,9 @@ cors:
media_root: '/home/inventree/data/media'
# STATIC_ROOT is the local filesystem location for storing static files
# By default, it is stored under /home/inventree
# By default, it is stored under /home/inventree/data/static
# Use environment variable INVENTREE_STATIC_ROOT
static_root: '/home/inventree/static'
static_root: '/home/inventree/data/static'
# Optional URL schemes to allow in URL fields
# By default, only the following schemes are allowed: ['http', 'https', 'ftp', 'ftps']

View File

@ -181,6 +181,14 @@
{% endif %}
{% endif %}
{% endif %}
{% if part.trackable and part.getLatestSerialNumber %}
<tr><td colspan="3"></td></tr>
<tr>
<td><span class='fas fa-hashtag'></span></td>
<td>{% trans "Latest Serial Number" %}</td>
<td>{{ part.getLatestSerialNumber }}{% include "clip.html"%}</td>
</tr>
{% endif %}
</table>
</div>
</div>

View File

@ -161,6 +161,13 @@ class StockItemSerializer(InvenTreeModelSerializer):
required_tests = serializers.IntegerField(source='required_test_count', read_only=True, required=False)
purchase_price = serializers.SerializerMethodField()
def get_purchase_price(self, obj):
""" Return purchase_price (Money field) as string (includes currency) """
return str(obj.purchase_price) if obj.purchase_price else '-'
def __init__(self, *args, **kwargs):
part_detail = kwargs.pop('part_detail', False)
@ -215,6 +222,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
'tracking_items',
'uid',
'updated',
'purchase_price',
]
""" These fields are read-only in this context.

View File

@ -660,6 +660,11 @@ function loadStockTable(table, options) {
title: '{% trans "Last Updated" %}',
sortable: true,
},
{
field: 'purchase_price',
title: '{% trans "Purchase Price" %}',
sortable: true,
},
{
field: 'packaging',
title: '{% trans "Packaging" %}',

View File

@ -7,6 +7,8 @@ ARG branch="master"
ENV PYTHONUNBUFFERED 1
# InvenTree key settings
# The INVENTREE_HOME directory is where the InvenTree source repository will be located
ENV INVENTREE_HOME="/home/inventree"
# GitHub settings
@ -17,10 +19,9 @@ ENV INVENTREE_LOG_LEVEL="INFO"
ENV INVENTREE_DOCKER="true"
# InvenTree paths
ENV INVENTREE_SRC_DIR="${INVENTREE_HOME}/src"
ENV INVENTREE_MNG_DIR="${INVENTREE_SRC_DIR}/InvenTree"
ENV INVENTREE_MNG_DIR="${INVENTREE_HOME}/InvenTree"
ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/data"
ENV INVENTREE_STATIC_ROOT="${INVENTREE_HOME}/static"
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static"
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
@ -44,8 +45,6 @@ RUN addgroup -S inventreegroup && adduser -S inventree -G inventreegroup
WORKDIR ${INVENTREE_HOME}
RUN mkdir -p ${INVENTREE_STATIC_ROOT}
# Install required system packages
RUN apk add --no-cache git make bash \
gcc libgcc g++ libstdc++ \
@ -78,37 +77,40 @@ RUN pip install --no-cache-dir -U gunicorn
FROM base as production
# Clone source code
RUN echo "Downloading InvenTree from ${INVENTREE_REPO}"
RUN git clone --branch ${INVENTREE_BRANCH} --depth 1 ${INVENTREE_REPO} ${INVENTREE_SRC_DIR}
RUN git clone --branch ${INVENTREE_BRANCH} --depth 1 ${INVENTREE_REPO} ${INVENTREE_HOME}
# Install InvenTree packages
RUN pip install --no-cache-dir -U -r ${INVENTREE_SRC_DIR}/requirements.txt
RUN pip install --no-cache-dir -U -r ${INVENTREE_HOME}/requirements.txt
# Copy gunicorn config file
COPY gunicorn.conf.py ${INVENTREE_HOME}/gunicorn.conf.py
# Copy startup scripts
COPY start_prod_server.sh ${INVENTREE_SRC_DIR}/start_prod_server.sh
COPY start_worker.sh ${INVENTREE_SRC_DIR}/start_worker.sh
COPY start_prod_server.sh ${INVENTREE_HOME}/start_prod_server.sh
COPY start_prod_worker.sh ${INVENTREE_HOME}/start_prod_worker.sh
RUN chmod 755 ${INVENTREE_SRC_DIR}/start_prod_server.sh
RUN chmod 755 ${INVENTREE_SRC_DIR}/start_worker.sh
RUN chmod 755 ${INVENTREE_HOME}/start_prod_server.sh
RUN chmod 755 ${INVENTREE_HOME}/start_prod_worker.sh
# exec commands should be executed from the "src" directory
WORKDIR ${INVENTREE_SRC_DIR}
WORKDIR ${INVENTREE_HOME}
# Let us begin
CMD ["bash", "./start_prod_server.sh"]
FROM base as dev
# The development image requires the source code to be mounted to /home/inventree/src/
# So from here, we don't actually "do" anything
# The development image requires the source code to be mounted to /home/inventree/
# So from here, we don't actually "do" anything, apart from some file management
WORKDIR ${INVENTREE_SRC_DIR}
ENV INVENTREE_DEV_DIR = "${INVENTREE_HOME}/dev"
COPY start_dev_server.sh ${INVENTREE_HOME}/start_dev_server.sh
COPY start_dev_worker.sh ${INVENTREE_HOME}/start_dev_worker.sh
RUN chmod 755 ${INVENTREE_HOME}/start_dev_server.sh
RUN chmod 755 ${INVENTREE_HOME}/start_dev_worker.sh
# Override default path settings
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DEV_DIR}/static"
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DEV_DIR}/media"
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DEV_DIR}/config.yaml"
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DEV_DIR}/secret_key.txt"
CMD ["bash", "/home/inventree/start_dev_server.sh"]
WORKDIR ${INVENTREE_HOME}
# Launch the development server
CMD ["bash", "/home/inventree/docker/start_dev_server.sh"]

View File

@ -1,7 +1,9 @@
INVENTREE_DB_ENGINE=sqlite3
INVENTREE_DB_NAME=/home/inventree/src/inventree_docker_dev.sqlite3
INVENTREE_MEDIA_ROOT=/home/inventree/src/inventree_media
INVENTREE_STATIC_ROOT=/home/inventree/src/inventree_static
INVENTREE_CONFIG_FILE=/home/inventree/src/config.yaml
INVENTREE_SECRET_KEY_FILE=/home/inventree/src/secret_key.txt
INVENTREE_DEBUG=true
INVENTREE_DB_NAME=/home/inventree/dev/inventree_db.sqlite3
INVENTREE_MEDIA_ROOT=/home/inventree/dev/media
INVENTREE_STATIC_ROOT=/home/inventree/dev/static
INVENTREE_CONFIG_FILE=/home/inventree/dev/config.yaml
INVENTREE_SECRET_KEY_FILE=/home/inventree/dev/secret_key.txt
INVENTREE_DEBUG=true
INVENTREE_WEB_ADDR=0.0.0.0
INVENTREE_WEB_PORT=8000

View File

@ -13,8 +13,8 @@ version: "3.8"
services:
# InvenTree web server services
# Uses gunicorn as the web server
inventree-server:
container_name: inventree-server
inventree-dev-server:
container_name: inventree-dev-server
build:
context: .
target: dev
@ -22,7 +22,7 @@ services:
- 8000:8000
volumes:
# Ensure you specify the location of the 'src' directory at the end of this file
- src:/home/inventree/src
- src:/home/inventree
env_file:
# Environment variables required for the dev server are configured in dev-config.env
- dev-config.env
@ -30,24 +30,24 @@ services:
restart: unless-stopped
# Background worker process handles long-running or periodic tasks
inventree-worker:
container_name: inventree-worker
inventree-dev-worker:
container_name: inventree-dev-worker
build:
context: .
target: dev
entrypoint: /home/inventree/start_dev_worker.sh
entrypoint: /home/inventree/docker/start_dev_worker.sh
depends_on:
- inventree-server
- inventree-dev-server
volumes:
# Ensure you specify the location of the 'src' directory at the end of this file
- src:/home/inventree/src
- src:/home/inventree
env_file:
# Environment variables required for the dev server are configured in dev-config.env
- dev-config.env
restart: unless-stopped
volumes:
# NOTE: Change /path/to/src to a directory on your local machine, where the InvenTree source code is located
# NOTE: Change "../" to a directory on your local machine, where the InvenTree source code is located
# Persistent data, stored external to the container(s)
src:
driver: local
@ -55,5 +55,5 @@ volumes:
type: none
o: bind
# This directory specified where InvenTree source code is stored "outside" the docker containers
# Note: This directory must conatin the file *manage.py*
device: /path/to/inventree/src
# By default, this directory is one level above the "docker" directory
device: ../

View File

@ -30,6 +30,7 @@ services:
- POSTGRES_USER=pguser
- POSTGRES_PASSWORD=pgpassword
volumes:
# Map 'data' volume such that postgres database is stored externally
- data:/var/lib/postgresql/data/
restart: unless-stopped
@ -43,8 +44,8 @@ services:
depends_on:
- inventree-db
volumes:
# Data volume must map to /home/inventree/data
- data:/home/inventree/data
- static:/home/inventree/static
environment:
# Default environment variables are configured to match the 'db' container
# Note: If you change the database image, these will need to be adjusted
@ -61,13 +62,13 @@ services:
inventree-worker:
container_name: inventree-worker
image: inventree/inventree:latest
entrypoint: ./start_worker.sh
entrypoint: ./start_prod_worker.sh
depends_on:
- inventree-db
- inventree-server
volumes:
# Data volume must map to /home/inventree/data
- data:/home/inventree/data
- static:/home/inventree/static
environment:
# Default environment variables are configured to match the 'db' container
# Note: If you change the database image, these will need to be adjusted
@ -81,7 +82,8 @@ services:
restart: unless-stopped
# nginx acts as a reverse proxy
# static files are served by nginx
# static files are served directly by nginx
# media files are served by nginx, although authentication is redirected to inventree-server
# web requests are redirected to gunicorn
# NOTE: You will need to provide a working nginx.conf file!
inventree-proxy:
@ -93,11 +95,11 @@ services:
# Change "1337" to the port that you want InvenTree web server to be available on
- 1337:80
volumes:
# Provide nginx.conf file to the container
# Provide ./nginx.conf file to the container
# Refer to the provided example file as a starting point
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
# Static data volume is mounted to /var/www/static
- static:/var/www/static:ro
# nginx proxy needs access to static and media files
- data:/var/www
restart: unless-stopped
volumes:
@ -110,6 +112,4 @@ volumes:
o: bind
# This directory specified where InvenTree data are stored "outside" the docker containers
# Change this path to a local system path where you want InvenTree data stored
device: /path/to/data
# Static files, shared between containers
static:
device: /path/to/data

View File

@ -1,3 +1,4 @@
server {
# Listen for connection on (internal) port 80
@ -34,4 +35,23 @@ server {
add_header Cache-Control "public";
}
# Redirect any requests for media files
location /media/ {
alias /var/www/media/;
# Media files require user authentication
auth_request /auth;
}
# Use the 'user' API endpoint for auth
location /auth {
internal;
proxy_pass http://inventree-server:8000/auth/;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}

View File

@ -16,21 +16,22 @@ if test -f "$INVENTREE_CONFIG_FILE"; then
echo "$INVENTREE_CONFIG_FILE exists - skipping"
else
echo "Copying config file to $INVENTREE_CONFIG_FILE"
cp $INVENTREE_SRC_DIR/InvenTree/config_template.yaml $INVENTREE_CONFIG_FILE
cp $INVENTREE_HOME/InvenTree/config_template.yaml $INVENTREE_CONFIG_FILE
fi
# Setup a virtual environment
python3 -m venv inventree-docker-dev
# Setup a virtual environment (within the "dev" directory)
python3 -m venv ./dev/env
source inventree-docker-dev/bin/activate
# Activate the virtual environment
source ./dev/env/bin/activate
echo "Installing required packages..."
pip install --no-cache-dir -U -r ${INVENTREE_SRC_DIR}/requirements.txt
pip install --no-cache-dir -U -r ${INVENTREE_HOME}/requirements.txt
echo "Starting InvenTree server..."
# Wait for the database to be ready
cd $INVENTREE_MNG_DIR
cd ${INVENTREE_HOME}/InvenTree
python manage.py wait_for_db
sleep 10
@ -45,4 +46,4 @@ python manage.py migrate --run-syncdb || exit 1
python manage.py clearsessions || exit 1
# Launch a development server
python manage.py runserver 0.0.0.0:$INVENTREE_WEB_PORT
python manage.py runserver ${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}

View File

@ -2,15 +2,15 @@
echo "Starting InvenTree worker..."
cd $INVENTREE_SRC_DIR
cd $INVENTREE_HOME
# Activate virtual environment
source inventree-docker-dev/bin/activate
source ./dev/env/bin/activate
sleep 5
# Wait for the database to be ready
cd $INVENTREE_MNG_DIR
cd InvenTree
python manage.py wait_for_db
sleep 10

View File

@ -16,7 +16,7 @@ if test -f "$INVENTREE_CONFIG_FILE"; then
echo "$INVENTREE_CONFIG_FILE exists - skipping"
else
echo "Copying config file to $INVENTREE_CONFIG_FILE"
cp $INVENTREE_SRC_DIR/InvenTree/config_template.yaml $INVENTREE_CONFIG_FILE
cp $INVENTREE_HOME/InvenTree/config_template.yaml $INVENTREE_CONFIG_FILE
fi
echo "Starting InvenTree server..."

View File

@ -1,6 +1,6 @@
invoke>=1.4.0 # Invoke build tool
wheel>=0.34.2 # Wheel
Django==3.2.2 # Django package
Django==3.2.4 # Django package
pillow==8.2.0 # Image manipulation
djangorestframework==3.12.4 # DRF framework
django-cors-headers==3.2.0 # CORS headers extension for DRF

View File

@ -282,7 +282,7 @@ def export_records(c, filename='data.json'):
tmpfile = f"{filename}.tmp"
cmd = f"dumpdata --indent 2 --output {tmpfile} {content_excludes()}"
cmd = f"dumpdata --indent 2 --output '{tmpfile}' {content_excludes()}"
# Dump data to temporary file
manage(c, cmd, pty=True)
@ -348,7 +348,7 @@ def import_records(c, filename='data.json'):
with open(tmpfile, "w") as f_out:
f_out.write(json.dumps(data, indent=2))
cmd = f"loaddata {tmpfile} -i {content_excludes()}"
cmd = f"loaddata '{tmpfile}' -i {content_excludes()}"
manage(c, cmd, pty=True)