mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge branch 'inventree:master' into stale
This commit is contained in:
commit
8799985f75
17
.github/workflows/welcome.yml
vendored
Normal file
17
.github/workflows/welcome.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# welcome new contributers
|
||||||
|
name: Welcome
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened]
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/first-interaction@v1
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
issue-message: 'Welcome to InvenTree! Please check the [contributing docs](https://inventree.readthedocs.io/en/latest/contribute/) on how to help.\nIf you experience setup / install issues please read all [install docs]( https://inventree.readthedocs.io/en/latest/start/intro/).'
|
||||||
|
pr-message: 'This is your first PR, welcome!\nPlease check [Contributing](https://github.com/inventree/InvenTree/blob/master/CONTRIBUTING.md) to make sure your submission fits our general code-style and workflow.\nMake sure to document why this PR is needed and to link connected issues so we can review it faster.'
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -49,6 +49,7 @@ static_i18n
|
|||||||
|
|
||||||
# Local config file
|
# Local config file
|
||||||
config.yaml
|
config.yaml
|
||||||
|
plugins.txt
|
||||||
|
|
||||||
# Default data file
|
# Default data file
|
||||||
data.json
|
data.json
|
||||||
|
90
InvenTree/InvenTree/config.py
Normal file
90
InvenTree/InvenTree/config.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"""
|
||||||
|
Helper functions for loading InvenTree configuration options
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_dir():
|
||||||
|
""" Returns the base (top-level) InvenTree directory """
|
||||||
|
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_file():
|
||||||
|
"""
|
||||||
|
Returns the path of the InvenTree configuration file.
|
||||||
|
|
||||||
|
Note: It will be created it if does not already exist!
|
||||||
|
"""
|
||||||
|
|
||||||
|
base_dir = get_base_dir()
|
||||||
|
|
||||||
|
cfg_filename = os.getenv('INVENTREE_CONFIG_FILE')
|
||||||
|
|
||||||
|
if cfg_filename:
|
||||||
|
cfg_filename = cfg_filename.strip()
|
||||||
|
cfg_filename = os.path.abspath(cfg_filename)
|
||||||
|
else:
|
||||||
|
# Config file is *not* specified - use the default
|
||||||
|
cfg_filename = os.path.join(base_dir, 'config.yaml')
|
||||||
|
|
||||||
|
if not os.path.exists(cfg_filename):
|
||||||
|
print("InvenTree configuration file 'config.yaml' not found - creating default file")
|
||||||
|
|
||||||
|
cfg_template = os.path.join(base_dir, "config_template.yaml")
|
||||||
|
shutil.copyfile(cfg_template, cfg_filename)
|
||||||
|
print(f"Created config file {cfg_filename}")
|
||||||
|
|
||||||
|
return cfg_filename
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_file():
|
||||||
|
"""
|
||||||
|
Returns the path of the InvenTree plugins specification file.
|
||||||
|
|
||||||
|
Note: It will be created if it does not already exist!
|
||||||
|
"""
|
||||||
|
# Check if the plugin.txt file (specifying required plugins) is specified
|
||||||
|
PLUGIN_FILE = os.getenv('INVENTREE_PLUGIN_FILE')
|
||||||
|
|
||||||
|
if not PLUGIN_FILE:
|
||||||
|
# If not specified, look in the same directory as the configuration file
|
||||||
|
|
||||||
|
config_dir = os.path.dirname(get_config_file())
|
||||||
|
|
||||||
|
PLUGIN_FILE = os.path.join(config_dir, 'plugins.txt')
|
||||||
|
|
||||||
|
if not os.path.exists(PLUGIN_FILE):
|
||||||
|
logger.warning("Plugin configuration file does not exist")
|
||||||
|
logger.info(f"Creating plugin file at '{PLUGIN_FILE}'")
|
||||||
|
|
||||||
|
# If opening the file fails (no write permission, for example), then this will throw an error
|
||||||
|
with open(PLUGIN_FILE, 'w') as plugin_file:
|
||||||
|
plugin_file.write("# InvenTree Plugins (uses PIP framework to install)\n\n")
|
||||||
|
|
||||||
|
return PLUGIN_FILE
|
||||||
|
|
||||||
|
|
||||||
|
def get_setting(environment_var, backup_val, default_value=None):
|
||||||
|
"""
|
||||||
|
Helper function for retrieving a configuration setting value
|
||||||
|
|
||||||
|
- First preference is to look for the environment variable
|
||||||
|
- Second preference is to look for the value of the settings file
|
||||||
|
- Third preference is the default value
|
||||||
|
"""
|
||||||
|
|
||||||
|
val = os.getenv(environment_var)
|
||||||
|
|
||||||
|
if val is not None:
|
||||||
|
return val
|
||||||
|
|
||||||
|
if backup_val is not None:
|
||||||
|
return backup_val
|
||||||
|
|
||||||
|
return default_value
|
@ -17,7 +17,6 @@ import os
|
|||||||
import random
|
import random
|
||||||
import socket
|
import socket
|
||||||
import string
|
import string
|
||||||
import shutil
|
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@ -28,30 +27,12 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from django.contrib.messages import constants as messages
|
from django.contrib.messages import constants as messages
|
||||||
import django.conf.locale
|
import django.conf.locale
|
||||||
|
|
||||||
|
from .config import get_base_dir, get_config_file, get_plugin_file, get_setting
|
||||||
|
|
||||||
|
|
||||||
def _is_true(x):
|
def _is_true(x):
|
||||||
# Shortcut function to determine if a value "looks" like a boolean
|
# Shortcut function to determine if a value "looks" like a boolean
|
||||||
return str(x).lower() in ['1', 'y', 'yes', 't', 'true']
|
return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true']
|
||||||
|
|
||||||
|
|
||||||
def get_setting(environment_var, backup_val, default_value=None):
|
|
||||||
"""
|
|
||||||
Helper function for retrieving a configuration setting value
|
|
||||||
|
|
||||||
- First preference is to look for the environment variable
|
|
||||||
- Second preference is to look for the value of the settings file
|
|
||||||
- Third preference is the default value
|
|
||||||
"""
|
|
||||||
|
|
||||||
val = os.getenv(environment_var)
|
|
||||||
|
|
||||||
if val is not None:
|
|
||||||
return val
|
|
||||||
|
|
||||||
if backup_val is not None:
|
|
||||||
return backup_val
|
|
||||||
|
|
||||||
return default_value
|
|
||||||
|
|
||||||
|
|
||||||
# Determine if we are running in "test" mode e.g. "manage.py test"
|
# Determine if we are running in "test" mode e.g. "manage.py test"
|
||||||
@ -61,27 +42,9 @@ TESTING = 'test' in sys.argv
|
|||||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = get_base_dir()
|
||||||
|
|
||||||
# Specify where the "config file" is located.
|
cfg_filename = get_config_file()
|
||||||
# By default, this is 'config.yaml'
|
|
||||||
|
|
||||||
cfg_filename = os.getenv('INVENTREE_CONFIG_FILE')
|
|
||||||
|
|
||||||
if cfg_filename:
|
|
||||||
cfg_filename = cfg_filename.strip()
|
|
||||||
cfg_filename = os.path.abspath(cfg_filename)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Config file is *not* specified - use the default
|
|
||||||
cfg_filename = os.path.join(BASE_DIR, 'config.yaml')
|
|
||||||
|
|
||||||
if not os.path.exists(cfg_filename):
|
|
||||||
print("InvenTree configuration file 'config.yaml' not found - creating default file")
|
|
||||||
|
|
||||||
cfg_template = os.path.join(BASE_DIR, "config_template.yaml")
|
|
||||||
shutil.copyfile(cfg_template, cfg_filename)
|
|
||||||
print(f"Created config file {cfg_filename}")
|
|
||||||
|
|
||||||
with open(cfg_filename, 'r') as cfg:
|
with open(cfg_filename, 'r') as cfg:
|
||||||
CONFIG = yaml.safe_load(cfg)
|
CONFIG = yaml.safe_load(cfg)
|
||||||
@ -89,6 +52,8 @@ with open(cfg_filename, 'r') as cfg:
|
|||||||
# We will place any config files in the same directory as the config file
|
# We will place any config files in the same directory as the config file
|
||||||
config_dir = os.path.dirname(cfg_filename)
|
config_dir = os.path.dirname(cfg_filename)
|
||||||
|
|
||||||
|
PLUGIN_FILE = get_plugin_file()
|
||||||
|
|
||||||
# Default action is to run the system in Debug mode
|
# Default action is to run the system in Debug mode
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = _is_true(get_setting(
|
DEBUG = _is_true(get_setting(
|
||||||
@ -908,8 +873,7 @@ MARKDOWNIFY_BLEACH = False
|
|||||||
# Maintenance mode
|
# Maintenance mode
|
||||||
MAINTENANCE_MODE_RETRY_AFTER = 60
|
MAINTENANCE_MODE_RETRY_AFTER = 60
|
||||||
|
|
||||||
|
# Plugin Directories (local plugins will be loaded from these directories)
|
||||||
# Plugins
|
|
||||||
PLUGIN_DIRS = ['plugin.builtin', ]
|
PLUGIN_DIRS = ['plugin.builtin', ]
|
||||||
|
|
||||||
if not TESTING:
|
if not TESTING:
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
|||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
{% load status_codes %}
|
{% load status_codes %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load l10n %}
|
||||||
|
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
{% inventree_title %} | {% trans "Stock Item" %} - {{ item }}
|
{% inventree_title %} | {% trans "Stock Item" %} - {{ item }}
|
||||||
@ -429,7 +430,7 @@ $("#stock-serialize").click(function() {
|
|||||||
part: {{ item.part.pk }},
|
part: {{ item.part.pk }},
|
||||||
reload: true,
|
reload: true,
|
||||||
data: {
|
data: {
|
||||||
quantity: {{ item.quantity }},
|
quantity: {{ item.quantity|unlocalize }},
|
||||||
{% if item.location %}
|
{% if item.location %}
|
||||||
destination: {{ item.location.pk }},
|
destination: {{ item.location.pk }},
|
||||||
{% elif item.part.default_location %}
|
{% elif item.part.default_location %}
|
||||||
|
@ -30,9 +30,11 @@ ENV INVENTREE_MNG_DIR="${INVENTREE_HOME}/InvenTree"
|
|||||||
ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/data"
|
ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/data"
|
||||||
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static"
|
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static"
|
||||||
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
|
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
|
||||||
|
ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DATA_DIR}/plugins"
|
||||||
|
|
||||||
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
|
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
|
||||||
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
|
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
|
||||||
|
ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DATA_DIR}/plugins.txt"
|
||||||
|
|
||||||
# Worker configuration (can be altered by user)
|
# Worker configuration (can be altered by user)
|
||||||
ENV INVENTREE_GUNICORN_WORKERS="4"
|
ENV INVENTREE_GUNICORN_WORKERS="4"
|
||||||
@ -129,8 +131,12 @@ ENV INVENTREE_PY_ENV="${INVENTREE_DEV_DIR}/env"
|
|||||||
# Override default path settings
|
# Override default path settings
|
||||||
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DEV_DIR}/static"
|
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DEV_DIR}/static"
|
||||||
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DEV_DIR}/media"
|
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DEV_DIR}/media"
|
||||||
|
ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DEV_DIR}/plugins"
|
||||||
|
|
||||||
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DEV_DIR}/config.yaml"
|
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DEV_DIR}/config.yaml"
|
||||||
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DEV_DIR}/secret_key.txt"
|
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DEV_DIR}/secret_key.txt"
|
||||||
|
ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DEV_DIR}/plugins.txt"
|
||||||
|
|
||||||
|
|
||||||
WORKDIR ${INVENTREE_HOME}
|
WORKDIR ${INVENTREE_HOME}
|
||||||
|
|
||||||
|
19
tasks.py
19
tasks.py
@ -71,17 +71,32 @@ def manage(c, cmd, pty=False):
|
|||||||
cmd=cmd
|
cmd=cmd
|
||||||
), pty=pty)
|
), pty=pty)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
|
def plugins(c):
|
||||||
|
"""
|
||||||
|
Installs all plugins as specified in 'plugins.txt'
|
||||||
|
"""
|
||||||
|
|
||||||
|
from InvenTree.InvenTree.config import get_plugin_file
|
||||||
|
|
||||||
|
plugin_file = get_plugin_file()
|
||||||
|
|
||||||
|
print(f"Installing plugin packages from '{plugin_file}'")
|
||||||
|
|
||||||
|
# Install the plugins
|
||||||
|
c.run(f"pip3 install -U -r '{plugin_file}'")
|
||||||
|
|
||||||
|
@task(post=[plugins])
|
||||||
def install(c):
|
def install(c):
|
||||||
"""
|
"""
|
||||||
Installs required python packages
|
Installs required python packages
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
print("Installing required python packages from 'requirements.txt'")
|
||||||
|
|
||||||
# Install required Python packages with PIP
|
# Install required Python packages with PIP
|
||||||
c.run('pip3 install -U -r requirements.txt')
|
c.run('pip3 install -U -r requirements.txt')
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def shell(c):
|
def shell(c):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user