mirror of
https://github.com/inventree/InvenTree.git
synced 2026-05-23 01:25:45 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
@@ -4,6 +4,8 @@ labels: ["question", "triage:not-checked", "setup"]
|
|||||||
body:
|
body:
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: deployment
|
id: deployment
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
attributes:
|
attributes:
|
||||||
label: "Deployment Method"
|
label: "Deployment Method"
|
||||||
options:
|
options:
|
||||||
@@ -12,6 +14,8 @@ body:
|
|||||||
- label: "Docker Production"
|
- label: "Docker Production"
|
||||||
- label: "Bare metal Development"
|
- label: "Bare metal Development"
|
||||||
- label: "Bare metal Production"
|
- label: "Bare metal Production"
|
||||||
|
- label: "Digital Ocean image"
|
||||||
|
- label: "Other (please provide a link `Steps to Reproduce`"
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
validations:
|
validations:
|
||||||
|
|||||||
@@ -15,33 +15,20 @@ env:
|
|||||||
- INVENTREE_PLUGIN_FILE=/opt/inventree/plugins.txt
|
- INVENTREE_PLUGIN_FILE=/opt/inventree/plugins.txt
|
||||||
- INVENTREE_CONFIG_FILE=/opt/inventree/config.yaml
|
- INVENTREE_CONFIG_FILE=/opt/inventree/config.yaml
|
||||||
after_install: contrib/packager.io/postinstall.sh
|
after_install: contrib/packager.io/postinstall.sh
|
||||||
|
dependencies:
|
||||||
|
- curl
|
||||||
|
- python3
|
||||||
|
- python3-venv
|
||||||
|
- python3-pip
|
||||||
|
- python3-cffi
|
||||||
|
- python3-brotli
|
||||||
|
- python3-wheel
|
||||||
|
- libpango-1.0-0
|
||||||
|
- libharfbuzz0b
|
||||||
|
- libpangoft2-1.0-0
|
||||||
|
- gettext
|
||||||
|
- nginx
|
||||||
|
- jq
|
||||||
targets:
|
targets:
|
||||||
ubuntu-20.04:
|
ubuntu-20.04: true
|
||||||
dependencies:
|
debian-11: true
|
||||||
- curl
|
|
||||||
- python3
|
|
||||||
- python3-venv
|
|
||||||
- python3-pip
|
|
||||||
- python3-cffi
|
|
||||||
- python3-brotli
|
|
||||||
- python3-wheel
|
|
||||||
- libpango-1.0-0
|
|
||||||
- libharfbuzz0b
|
|
||||||
- libpangoft2-1.0-0
|
|
||||||
- gettext
|
|
||||||
- nginx
|
|
||||||
- jq
|
|
||||||
debian-11:
|
|
||||||
dependencies:
|
|
||||||
- curl
|
|
||||||
- python3
|
|
||||||
- python3-venv
|
|
||||||
- python3-pip
|
|
||||||
- python3-cffi
|
|
||||||
- python3-brotli
|
|
||||||
- python3-wheel
|
|
||||||
- libpango-1.0-0
|
|
||||||
- libpangoft2-1.0-0
|
|
||||||
- gettext
|
|
||||||
- nginx
|
|
||||||
- jq
|
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 82
|
INVENTREE_API_VERSION = 83
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||||
|
|
||||||
|
v83 -> 2022-11-19 : https://github.com/inventree/InvenTree/pull/3949
|
||||||
|
- Add support for structural Stock locations
|
||||||
|
|
||||||
v82 -> 2022-11-16 : https://github.com/inventree/InvenTree/pull/3931
|
v82 -> 2022-11-16 : https://github.com/inventree/InvenTree/pull/3931
|
||||||
- Add support for structural Part categories
|
- Add support for structural Part categories
|
||||||
|
|
||||||
|
|||||||
@@ -744,6 +744,7 @@ SOCIALACCOUNT_STORE_TOKENS = True
|
|||||||
# settings for allauth
|
# settings for allauth
|
||||||
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', 'login_confirm_days', 3, typecast=int)
|
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', 'login_confirm_days', 3, typecast=int)
|
||||||
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', 'login_attempts', 5, typecast=int)
|
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', 'login_attempts', 5, typecast=int)
|
||||||
|
ACCOUNT_DEFAULT_HTTP_PROTOCOL = get_setting('INVENTREE_LOGIN_DEFAULT_HTTP_PROTOCOL', 'login_default_protocol', 'http')
|
||||||
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
|
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
|
||||||
ACCOUNT_PREVENT_ENUMERATION = True
|
ACCOUNT_PREVENT_ENUMERATION = True
|
||||||
|
|
||||||
|
|||||||
@@ -458,7 +458,7 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.part-thumb-container:hover .part-thumb-overlay {
|
.part-thumb-container:hover .part-thumb-overlay {
|
||||||
opacity: 1;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
.part-thumb-overlay {
|
.part-thumb-overlay {
|
||||||
@@ -467,8 +467,6 @@ main {
|
|||||||
left: 0;
|
left: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: .25s ease;
|
transition: .25s ease;
|
||||||
padding-top: 10px;
|
|
||||||
padding-left: 25px;
|
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import re
|
|||||||
import warnings
|
import warnings
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Callable
|
from typing import Callable, List
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import mail as django_mail
|
from django.core import mail as django_mail
|
||||||
@@ -153,7 +153,7 @@ class ScheduledTask:
|
|||||||
|
|
||||||
class TaskRegister:
|
class TaskRegister:
|
||||||
"""Registery for periodicall tasks."""
|
"""Registery for periodicall tasks."""
|
||||||
task_list: list[ScheduledTask] = []
|
task_list: List[ScheduledTask] = []
|
||||||
|
|
||||||
def register(self, task, schedule, minutes: int = None):
|
def register(self, task, schedule, minutes: int = None):
|
||||||
"""Register a task with the que."""
|
"""Register a task with the que."""
|
||||||
|
|||||||
@@ -3,23 +3,7 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from InvenTree.forms import HelperForm
|
|
||||||
|
|
||||||
from .files import FileManager
|
from .files import FileManager
|
||||||
from .models import InvenTreeSetting
|
|
||||||
|
|
||||||
|
|
||||||
class SettingEditForm(HelperForm):
|
|
||||||
"""Form for creating / editing a settings object."""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""Metaclassoptions for SettingEditForm."""
|
|
||||||
|
|
||||||
model = InvenTreeSetting
|
|
||||||
|
|
||||||
fields = [
|
|
||||||
'value'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class UploadFileForm(forms.Form):
|
class UploadFileForm(forms.Form):
|
||||||
|
|||||||
@@ -58,6 +58,9 @@
|
|||||||
{% if allow_download %}
|
{% if allow_download %}
|
||||||
<button type='button' class='btn btn-outline-secondary' title="{% trans 'Download image from URL' %}" id='company-image-url'><span class='fas fa-cloud-download-alt'></span></button>
|
<button type='button' class='btn btn-outline-secondary' title="{% trans 'Download image from URL' %}" id='company-image-url'><span class='fas fa-cloud-download-alt'></span></button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if company.image %}
|
||||||
|
<button type='button' class='btn btn-outline-secondary' title='{% trans "Delete image" %}' id='company-image-delete'><span class='fas fa-trash-alt icon-red'></span></button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -194,10 +197,37 @@
|
|||||||
$('#company-image').click(function() {
|
$('#company-image').click(function() {
|
||||||
showModalImage('{{ company.image.url }}');
|
showModalImage('{{ company.image.url }}');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#company-image-delete').click(function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
showQuestionDialog(
|
||||||
|
'{% trans "Remove Image" %}',
|
||||||
|
'{% trans "Remove associated image from this company" %}',
|
||||||
|
{
|
||||||
|
accept_text: '{% trans "Remove" %}',
|
||||||
|
submitClass: 'danger',
|
||||||
|
accept: function() {
|
||||||
|
inventreePut(
|
||||||
|
'{% url "api-company-detail" company.pk %}',
|
||||||
|
{
|
||||||
|
'image': null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'PATCH',
|
||||||
|
success: function() {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
$("#company-image-upload").click(function() {
|
$("#company-image-upload").click(function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
constructForm(
|
constructForm(
|
||||||
'{% url "api-company-detail" company.pk %}',
|
'{% url "api-company-detail" company.pk %}',
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ background:
|
|||||||
# Login configuration
|
# Login configuration
|
||||||
login_confirm_days: 3
|
login_confirm_days: 3
|
||||||
login_attempts: 5
|
login_attempts: 5
|
||||||
|
login_default_protocol: http
|
||||||
|
|
||||||
# Remote / proxy login
|
# Remote / proxy login
|
||||||
# These settings can introduce security problems if configured incorrectly. Please read
|
# These settings can introduce security problems if configured incorrectly. Please read
|
||||||
|
|||||||
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
+2123
-1808
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
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
@@ -14,6 +14,6 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='partcategory',
|
model_name='partcategory',
|
||||||
name='structural',
|
name='structural',
|
||||||
field=models.BooleanField(default=False, help_text="Parts may not be directly assigned to a structural category, but may be assigned to it's child categories.", verbose_name='Structural'),
|
field=models.BooleanField(default=False, help_text="Parts may not be directly assigned to a structural category, but may be assigned to child categories.", verbose_name='Structural'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class PartCategory(MetadataMixin, InvenTreeTree):
|
|||||||
verbose_name=_('Structural'),
|
verbose_name=_('Structural'),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
'Parts may not be directly assigned to a structural category, '
|
'Parts may not be directly assigned to a structural category, '
|
||||||
'but may be assigned to it\'s child categories.'),
|
'but may be assigned to child categories.'),
|
||||||
)
|
)
|
||||||
|
|
||||||
default_keywords = models.CharField(null=True, blank=True, max_length=250, verbose_name=_('Default keywords'), help_text=_('Default keywords for parts in this category'))
|
default_keywords = models.CharField(null=True, blank=True, max_length=250, verbose_name=_('Default keywords'), help_text=_('Default keywords for parts in this category'))
|
||||||
|
|||||||
@@ -502,8 +502,34 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#part-image-upload").click(function() {
|
$('#part-image-delete').click(function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
showQuestionDialog(
|
||||||
|
'{% trans "Remove Image" %}',
|
||||||
|
'{% trans "Remove associated image from this part" %}',
|
||||||
|
{
|
||||||
|
accept_text: '{% trans "Remove" %}',
|
||||||
|
submitClass: 'danger',
|
||||||
|
accept: function() {
|
||||||
|
inventreePut(
|
||||||
|
'{% url "api-part-detail" part.pk %}',
|
||||||
|
{
|
||||||
|
'image': null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'PATCH',
|
||||||
|
success: function(data) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#part-image-upload").click(function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
constructForm(
|
constructForm(
|
||||||
'{% url "api-part-detail" part.pk %}',
|
'{% url "api-part-detail" part.pk %}',
|
||||||
{
|
{
|
||||||
@@ -576,12 +602,12 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#part-image-select").click(function() {
|
$("#part-image-select").click(function(event) {
|
||||||
launchModalForm("{% url 'part-image-select' part.id %}",
|
event.stopPropagation();
|
||||||
{
|
launchModalForm("{% url 'part-image-select' part.id %}", {
|
||||||
reload: true,
|
reload: true,
|
||||||
after_render: onSelectImage
|
after_render: onSelectImage
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#part-edit").click(function() {
|
$("#part-edit").click(function() {
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
{% if allow_download %}
|
{% if allow_download %}
|
||||||
<button type='button' class='btn btn-outline-secondary' title="{% trans 'Download image from URL' %}" id='part-image-url'><span class='fas fa-cloud-download-alt'></span></button>
|
<button type='button' class='btn btn-outline-secondary' title="{% trans 'Download image from URL' %}" id='part-image-url'><span class='fas fa-cloud-download-alt'></span></button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if part.image %}
|
||||||
|
<button type='button' class='btn btn-outline-secondary' title='{% trans "Delete image" %}' id='part-image-delete'><span class='fas fa-trash-alt icon-red'></span></button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -309,6 +309,8 @@ class StockLocationList(APIDownloadMixin, ListCreateAPI):
|
|||||||
]
|
]
|
||||||
|
|
||||||
filterset_fields = [
|
filterset_fields = [
|
||||||
|
'name',
|
||||||
|
'structural'
|
||||||
]
|
]
|
||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2.16 on 2022-11-18 15:49
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('stock', '0089_alter_stockitem_purchase_price'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stocklocation',
|
||||||
|
name='structural',
|
||||||
|
field=models.BooleanField(default=False, help_text="Stock items may not be directly located into a structural stock locations, but may be located to child locations.", verbose_name='Structural'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -107,6 +107,14 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
|||||||
help_text=_('Select Owner'),
|
help_text=_('Select Owner'),
|
||||||
related_name='stock_locations')
|
related_name='stock_locations')
|
||||||
|
|
||||||
|
structural = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name=_('Structural'),
|
||||||
|
help_text=_(
|
||||||
|
'Stock items may not be directly located into a structural stock locations, '
|
||||||
|
'but may be located to child locations.'),
|
||||||
|
)
|
||||||
|
|
||||||
def get_location_owner(self):
|
def get_location_owner(self):
|
||||||
"""Get the closest "owner" for this location.
|
"""Get the closest "owner" for this location.
|
||||||
|
|
||||||
@@ -139,6 +147,17 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
|
|||||||
|
|
||||||
return user in owner.get_related_owners(include_group=True)
|
return user in owner.get_related_owners(include_group=True)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
"""Custom clean action for the StockLocation model:
|
||||||
|
|
||||||
|
- Ensure stock location can't be made structural if stock items already located to them
|
||||||
|
"""
|
||||||
|
if self.pk and self.structural and self.item_count > 0:
|
||||||
|
raise ValidationError(
|
||||||
|
_("You cannot make this stock location structural because some stock items "
|
||||||
|
"are already located into it!"))
|
||||||
|
super().clean()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Return url for instance."""
|
"""Return url for instance."""
|
||||||
return reverse('stock-location-detail', kwargs={'pk': self.id})
|
return reverse('stock-location-detail', kwargs={'pk': self.id})
|
||||||
@@ -496,8 +515,14 @@ class StockItem(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
|
|||||||
- The 'part' and 'supplier_part.part' fields cannot point to the same Part object
|
- The 'part' and 'supplier_part.part' fields cannot point to the same Part object
|
||||||
- The 'part' is not virtual
|
- The 'part' is not virtual
|
||||||
- The 'part' does not belong to itself
|
- The 'part' does not belong to itself
|
||||||
|
- The location is not structural
|
||||||
- Quantity must be 1 if the StockItem has a serial number
|
- Quantity must be 1 if the StockItem has a serial number
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.location is not None and self.location.structural:
|
||||||
|
raise ValidationError(
|
||||||
|
{'location': _("Stock items cannot be located into structural stock locations!")})
|
||||||
|
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
# Strip serial number field
|
# Strip serial number field
|
||||||
|
|||||||
@@ -606,6 +606,7 @@ class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
'items',
|
'items',
|
||||||
'owner',
|
'owner',
|
||||||
'icon',
|
'icon',
|
||||||
|
'structural',
|
||||||
]
|
]
|
||||||
|
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from datetime import datetime, timedelta
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
|
||||||
import django.http
|
import django.http
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
import tablib
|
import tablib
|
||||||
@@ -225,6 +226,71 @@ class StockLocationTest(StockAPITestCase):
|
|||||||
child.refresh_from_db()
|
child.refresh_from_db()
|
||||||
self.assertEqual(child.parent, parent_stock_location)
|
self.assertEqual(child.parent, parent_stock_location)
|
||||||
|
|
||||||
|
def test_stock_location_structural(self):
|
||||||
|
"""Test the effectiveness of structural stock locations
|
||||||
|
|
||||||
|
Make sure:
|
||||||
|
- Stock items cannot be created in structural locations
|
||||||
|
- Stock items cannot be located to structural locations
|
||||||
|
- Check that stock location change to structural fails if items located into it
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Create our structural stock location
|
||||||
|
structural_location = StockLocation.objects.create(
|
||||||
|
name='Structural stock location',
|
||||||
|
description='This is the structural stock location',
|
||||||
|
parent=None,
|
||||||
|
structural=True
|
||||||
|
)
|
||||||
|
|
||||||
|
stock_item_count_before = StockItem.objects.count()
|
||||||
|
|
||||||
|
# Make sure that we get an error if we try to create a stock item in the structural location
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
item = StockItem.objects.create(
|
||||||
|
batch="Stock item which shall not be created",
|
||||||
|
location=structural_location
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure that the stock item really did not get created in the structural location
|
||||||
|
self.assertEqual(stock_item_count_before, StockItem.objects.count())
|
||||||
|
|
||||||
|
# Create a non-structural location for test stock location change
|
||||||
|
non_structural_location = StockLocation.objects.create(
|
||||||
|
name='Non-structural category',
|
||||||
|
description='This is a non-structural category',
|
||||||
|
parent=None,
|
||||||
|
structural=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# Construct a part for stock item creation
|
||||||
|
part = Part.objects.create(
|
||||||
|
name='Part for stock item creation', description='Part for stock item creation',
|
||||||
|
category=None,
|
||||||
|
is_template=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create the test stock item located to a non-structural category
|
||||||
|
item = StockItem.objects.create(
|
||||||
|
batch="Item which will be tried to relocated to a structural location",
|
||||||
|
location=non_structural_location,
|
||||||
|
part=part
|
||||||
|
)
|
||||||
|
|
||||||
|
# Try to relocate it to a structural location
|
||||||
|
item.location = structural_location
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
# Ensure that the item did not get saved to the DB
|
||||||
|
item.refresh_from_db()
|
||||||
|
self.assertEqual(item.location.pk, non_structural_location.pk)
|
||||||
|
|
||||||
|
# Try to change the non-structural location to structural while items located into it
|
||||||
|
non_structural_location.structural = True
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
non_structural_location.full_clean()
|
||||||
|
|
||||||
|
|
||||||
class StockItemListTest(StockAPITestCase):
|
class StockItemListTest(StockAPITestCase):
|
||||||
"""Tests for the StockItem API LIST endpoint."""
|
"""Tests for the StockItem API LIST endpoint."""
|
||||||
|
|||||||
@@ -60,9 +60,15 @@ function buildFormFields() {
|
|||||||
},
|
},
|
||||||
take_from: {
|
take_from: {
|
||||||
icon: 'fa-sitemap',
|
icon: 'fa-sitemap',
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
destination: {
|
destination: {
|
||||||
icon: 'fa-sitemap',
|
icon: 'fa-sitemap',
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
icon: 'fa-link',
|
icon: 'fa-link',
|
||||||
@@ -524,7 +530,11 @@ function completeBuildOutputs(build_id, outputs, options={}) {
|
|||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
fields: {
|
fields: {
|
||||||
status: {},
|
status: {},
|
||||||
location: {},
|
location: {
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
notes: {},
|
notes: {},
|
||||||
accept_incomplete_allocation: {},
|
accept_incomplete_allocation: {},
|
||||||
},
|
},
|
||||||
@@ -2391,7 +2401,7 @@ function autoAllocateStockToBuild(build_id, bom_items=[], options={}) {
|
|||||||
<strong>{% trans "Automatic Stock Allocation" %}</strong><br>
|
<strong>{% trans "Automatic Stock Allocation" %}</strong><br>
|
||||||
{% trans "Stock items will be automatically allocated to this build order, according to the provided guidelines" %}:
|
{% trans "Stock items will be automatically allocated to this build order, according to the provided guidelines" %}:
|
||||||
<ul>
|
<ul>
|
||||||
<li>{% trans "If a location is specifed, stock will only be allocated from that location" %}</li>
|
<li>{% trans "If a location is specified, stock will only be allocated from that location" %}</li>
|
||||||
<li>{% trans "If stock is considered interchangeable, it will be allocated from the first location it is found" %}</li>
|
<li>{% trans "If stock is considered interchangeable, it will be allocated from the first location it is found" %}</li>
|
||||||
<li>{% trans "If substitute stock is allowed, it will be used where stock of the primary part cannot be found" %}</li>
|
<li>{% trans "If substitute stock is allowed, it will be used where stock of the primary part cannot be found" %}</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -2401,6 +2411,9 @@ function autoAllocateStockToBuild(build_id, bom_items=[], options={}) {
|
|||||||
var fields = {
|
var fields = {
|
||||||
location: {
|
location: {
|
||||||
value: options.location,
|
value: options.location,
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
exclude_location: {},
|
exclude_location: {},
|
||||||
interchangeable: {
|
interchangeable: {
|
||||||
|
|||||||
@@ -621,11 +621,11 @@ function showQuestionDialog(title, content, options={}) {
|
|||||||
* cancel - Functino to run if the user presses 'Cancel'
|
* cancel - Functino to run if the user presses 'Cancel'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var modal = createNewModal({
|
options.title = title;
|
||||||
title: title,
|
options.submitText = options.accept_text || '{% trans "Accept" %}';
|
||||||
submitText: options.accept_text || '{% trans "Accept" %}',
|
options.closeText = options.cancel_text || '{% trans "Cancel" %}';
|
||||||
closeText: options.cancel_text || '{% trans "Cancel" %}',
|
|
||||||
});
|
var modal = createNewModal(options);
|
||||||
|
|
||||||
modalSetContent(modal, content);
|
modalSetContent(modal, content);
|
||||||
|
|
||||||
|
|||||||
@@ -888,7 +888,11 @@ function poLineItemFields(options={}) {
|
|||||||
purchase_price: {},
|
purchase_price: {},
|
||||||
purchase_price_currency: {},
|
purchase_price_currency: {},
|
||||||
target_date: {},
|
target_date: {},
|
||||||
destination: {},
|
destination: {
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
notes: {},
|
notes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1688,7 +1692,11 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
|||||||
constructForm(`/api/order/po/${order_id}/receive/`, {
|
constructForm(`/api/order/po/${order_id}/receive/`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: {
|
fields: {
|
||||||
location: {},
|
location: {
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
confirm: true,
|
confirm: true,
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ function partFields(options={}) {
|
|||||||
icon: 'fa-link',
|
icon: 'fa-link',
|
||||||
},
|
},
|
||||||
default_location: {
|
default_location: {
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
default_supplier: {
|
default_supplier: {
|
||||||
filters: {
|
filters: {
|
||||||
@@ -297,7 +300,11 @@ function categoryFields() {
|
|||||||
},
|
},
|
||||||
name: {},
|
name: {},
|
||||||
description: {},
|
description: {},
|
||||||
default_location: {},
|
default_location: {
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
default_keywords: {
|
default_keywords: {
|
||||||
icon: 'fa-key',
|
icon: 'fa-key',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ function serializeStockItem(pk, options={}) {
|
|||||||
},
|
},
|
||||||
destination: {
|
destination: {
|
||||||
icon: 'fa-sitemap',
|
icon: 'fa-sitemap',
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
notes: {},
|
notes: {},
|
||||||
};
|
};
|
||||||
@@ -114,6 +117,7 @@ function stockLocationFields(options={}) {
|
|||||||
name: {},
|
name: {},
|
||||||
description: {},
|
description: {},
|
||||||
owner: {},
|
owner: {},
|
||||||
|
structural: {},
|
||||||
icon: {
|
icon: {
|
||||||
help_text: `{% trans "Icon (optional) - Explore all available icons on" %} <a href="https://fontawesome.com/v5/search?s=solid" target="_blank" rel="noopener noreferrer">Font Awesome</a>.`,
|
help_text: `{% trans "Icon (optional) - Explore all available icons on" %} <a href="https://fontawesome.com/v5/search?s=solid" target="_blank" rel="noopener noreferrer">Font Awesome</a>.`,
|
||||||
placeholder: 'fas fa-box',
|
placeholder: 'fas fa-box',
|
||||||
@@ -280,6 +284,9 @@ function stockItemFields(options={}) {
|
|||||||
},
|
},
|
||||||
location: {
|
location: {
|
||||||
icon: 'fa-sitemap',
|
icon: 'fa-sitemap',
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
quantity: {
|
quantity: {
|
||||||
help_text: '{% trans "Enter initial quantity for this stock item" %}',
|
help_text: '{% trans "Enter initial quantity for this stock item" %}',
|
||||||
@@ -838,6 +845,9 @@ function mergeStockItems(items, options={}) {
|
|||||||
location: {
|
location: {
|
||||||
value: location,
|
value: location,
|
||||||
icon: 'fa-sitemap',
|
icon: 'fa-sitemap',
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
notes: {},
|
notes: {},
|
||||||
allow_mismatched_suppliers: {},
|
allow_mismatched_suppliers: {},
|
||||||
@@ -1106,7 +1116,11 @@ function adjustStock(action, items, options={}) {
|
|||||||
var extraFields = {};
|
var extraFields = {};
|
||||||
|
|
||||||
if (specifyLocation) {
|
if (specifyLocation) {
|
||||||
extraFields.location = {};
|
extraFields.location = {
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action != 'delete') {
|
if (action != 'delete') {
|
||||||
@@ -2810,6 +2824,9 @@ function uninstallStockItem(installed_item_id, options={}) {
|
|||||||
fields: {
|
fields: {
|
||||||
location: {
|
location: {
|
||||||
icon: 'fa-sitemap',
|
icon: 'fa-sitemap',
|
||||||
|
filters: {
|
||||||
|
structural: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
note: {},
|
note: {},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ There are several options to deploy InvenTree.
|
|||||||
<div align="center"><h4>
|
<div align="center"><h4>
|
||||||
<a href="https://inventree.readthedocs.io/en/latest/start/docker/">Docker</a>
|
<a href="https://inventree.readthedocs.io/en/latest/start/docker/">Docker</a>
|
||||||
<span> · </span>
|
<span> · </span>
|
||||||
<a href="https://marketplace.digitalocean.com/apps/inventree?refcode=d6172576d014"><img src="https://www.deploytodo.com/do-btn-blue-ghost.svg" alt="Deploy to DO" width="auto" height="40" /></a>
|
|
||||||
<span> · </span>
|
|
||||||
<a href="https://inventree.readthedocs.io/en/latest/start/install/">Bare Metal</a>
|
<a href="https://inventree.readthedocs.io/en/latest/start/install/">Bare Metal</a>
|
||||||
</h4></div>
|
</h4></div>
|
||||||
|
|
||||||
|
|||||||
+22
-52
@@ -2,16 +2,12 @@
|
|||||||
# This script was generated by bashly 0.8.9 (https://bashly.dannyb.co)
|
# This script was generated by bashly 0.8.9 (https://bashly.dannyb.co)
|
||||||
# Modifying it manually is not recommended
|
# Modifying it manually is not recommended
|
||||||
|
|
||||||
# :wrapper.bash3_bouncer
|
|
||||||
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
|
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
|
||||||
printf "bash version 4 or higher is required\n" >&2
|
printf "bash version 4 or higher is required\n" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# :command.master_script
|
|
||||||
# :command.root_command
|
|
||||||
root_command() {
|
root_command() {
|
||||||
# src/root_command.sh
|
|
||||||
# Settings
|
# Settings
|
||||||
source_url=${args[source]}
|
source_url=${args[source]}
|
||||||
publisher=${args[publisher]}
|
publisher=${args[publisher]}
|
||||||
@@ -59,25 +55,26 @@ root_command() {
|
|||||||
# Check if os and version is supported
|
# Check if os and version is supported
|
||||||
get_distribution
|
get_distribution
|
||||||
echo "### Detected distribution: $OS $VER"
|
echo "### Detected distribution: $OS $VER"
|
||||||
NOT_SUPPORTED=false
|
SUPPORTED=true
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
Ubuntu)
|
Ubuntu)
|
||||||
if [[ $VER != "20.04" ]]; then
|
if [[ $VER != "20.04" ]]; then
|
||||||
NOT_SUPPORTED=true
|
SUPPORTED=false
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
Debian | Raspbian)
|
"Debian GNU/Linux" | Raspbian)
|
||||||
if [[ $VER != "11" ]]; then
|
if [[ $VER != "11" ]]; then
|
||||||
NOT_SUPPORTED=true
|
SUPPORTED=false
|
||||||
fi
|
fi
|
||||||
|
OS=Debian
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "### Distribution not supported"
|
echo "### Distribution not supported"
|
||||||
NOT_SUPPORTED=true
|
SUPPORTED=false
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ $NOT_SUPPORTED ]]; then
|
if [[ $SUPPORTED != "true" ]]; then
|
||||||
echo "This OS is currently not supported"
|
echo "This OS is currently not supported"
|
||||||
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
|
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
|
||||||
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
|
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
|
||||||
@@ -96,11 +93,10 @@ root_command() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "### Adding key and package source"
|
echo "### Getting and adding key"
|
||||||
# Add key
|
wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -
|
||||||
do_call "wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -"
|
echo "### Adding package source"
|
||||||
# Add packagelist
|
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${OS,,}/${VER}.repo"
|
||||||
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${lsb_dist}/${dist_version}.repo"
|
|
||||||
|
|
||||||
echo "### Updateing package lists"
|
echo "### Updateing package lists"
|
||||||
do_call "sudo apt-get update"
|
do_call "sudo apt-get update"
|
||||||
@@ -118,34 +114,30 @@ root_command() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# :command.version_command
|
|
||||||
version_command() {
|
version_command() {
|
||||||
echo "$version"
|
echo "$version"
|
||||||
}
|
}
|
||||||
|
|
||||||
# :command.usage
|
install.sh_usage() {
|
||||||
install_usage() {
|
|
||||||
if [[ -n $long_usage ]]; then
|
if [[ -n $long_usage ]]; then
|
||||||
printf "install - Interactive installer for InvenTree\n"
|
printf "install.sh - Interactive installer for InvenTree\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
else
|
else
|
||||||
printf "install - Interactive installer for InvenTree\n"
|
printf "install.sh - Interactive installer for InvenTree\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf "Usage:\n"
|
printf "Usage:\n"
|
||||||
printf " install [SOURCE] [PUBLISHER] [OPTIONS]\n"
|
printf " install.sh [SOURCE] [PUBLISHER] [OPTIONS]\n"
|
||||||
printf " install --help | -h\n"
|
printf " install.sh --help | -h\n"
|
||||||
printf " install --version | -v\n"
|
printf " install.sh --version | -v\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# :command.long_usage
|
|
||||||
if [[ -n $long_usage ]]; then
|
if [[ -n $long_usage ]]; then
|
||||||
printf "Options:\n"
|
printf "Options:\n"
|
||||||
|
|
||||||
# :command.usage_fixed_flags
|
|
||||||
echo " --help, -h"
|
echo " --help, -h"
|
||||||
printf " Show this help\n"
|
printf " Show this help\n"
|
||||||
echo
|
echo
|
||||||
@@ -153,34 +145,27 @@ install_usage() {
|
|||||||
printf " Show version number\n"
|
printf " Show version number\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# :command.usage_flags
|
|
||||||
# :flag.usage
|
|
||||||
echo " --no-call, -n"
|
echo " --no-call, -n"
|
||||||
printf " Do not call outside APIs (only functionally needed)\n"
|
printf " Do not call outside APIs (only functionally needed)\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# :flag.usage
|
|
||||||
echo " --dry-run, -d"
|
echo " --dry-run, -d"
|
||||||
printf " Dry run (do not install anything)\n"
|
printf " Dry run (do not install anything)\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# :command.usage_args
|
|
||||||
printf "Arguments:\n"
|
printf "Arguments:\n"
|
||||||
|
|
||||||
# :argument.usage
|
|
||||||
echo " SOURCE"
|
echo " SOURCE"
|
||||||
printf " Package source that should be used\n"
|
printf " Package source that should be used\n"
|
||||||
printf " Allowed: stable, master, main\n"
|
printf " Allowed: stable, master, main\n"
|
||||||
printf " Default: stable\n"
|
printf " Default: stable\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# :argument.usage
|
|
||||||
echo " PUBLISHER"
|
echo " PUBLISHER"
|
||||||
printf " Publisher that should be used\n"
|
printf " Publisher that should be used\n"
|
||||||
printf " Default: inventree\n"
|
printf " Default: inventree\n"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# :command.usage_examples
|
|
||||||
printf "Examples:\n"
|
printf "Examples:\n"
|
||||||
printf " install\n"
|
printf " install\n"
|
||||||
printf " install master --no-call\n"
|
printf " install master --no-call\n"
|
||||||
@@ -190,7 +175,6 @@ install_usage() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# :command.normalize_input
|
|
||||||
normalize_input() {
|
normalize_input() {
|
||||||
local arg flags
|
local arg flags
|
||||||
|
|
||||||
@@ -214,7 +198,7 @@ normalize_input() {
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
# :command.inspect_args
|
|
||||||
inspect_args() {
|
inspect_args() {
|
||||||
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
|
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
|
||||||
if (( ${#args[@]} )); then
|
if (( ${#args[@]} )); then
|
||||||
@@ -234,11 +218,8 @@ inspect_args() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# :command.command_functions
|
|
||||||
|
|
||||||
# :command.parse_requirements
|
|
||||||
parse_requirements() {
|
parse_requirements() {
|
||||||
# :command.fixed_flags_filter
|
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
--version | -v )
|
--version | -v )
|
||||||
version_command
|
version_command
|
||||||
@@ -247,31 +228,26 @@ parse_requirements() {
|
|||||||
|
|
||||||
--help | -h )
|
--help | -h )
|
||||||
long_usage=yes
|
long_usage=yes
|
||||||
install_usage
|
install.sh_usage
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# :command.command_filter
|
|
||||||
action="root"
|
action="root"
|
||||||
|
|
||||||
# :command.parse_requirements_while
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
key="$1"
|
key="$1"
|
||||||
case "$key" in
|
case "$key" in
|
||||||
# :flag.case
|
|
||||||
--no-call | -n )
|
--no-call | -n )
|
||||||
|
|
||||||
# :flag.case_no_arg
|
|
||||||
args[--no-call]=1
|
args[--no-call]=1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
|
||||||
# :flag.case
|
|
||||||
--dry-run | -d )
|
--dry-run | -d )
|
||||||
|
|
||||||
# :flag.case_no_arg
|
|
||||||
args[--dry-run]=1
|
args[--dry-run]=1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
@@ -282,8 +258,7 @@ parse_requirements() {
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
# :command.parse_requirements_case
|
|
||||||
# :command.parse_requirements_case_simple
|
|
||||||
if [[ -z ${args[source]+x} ]]; then
|
if [[ -z ${args[source]+x} ]]; then
|
||||||
|
|
||||||
args[source]=$1
|
args[source]=$1
|
||||||
@@ -302,11 +277,9 @@ parse_requirements() {
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# :command.default_assignments
|
|
||||||
[[ -n ${args[source]:-} ]] || args[source]="stable"
|
[[ -n ${args[source]:-} ]] || args[source]="stable"
|
||||||
[[ -n ${args[publisher]:-} ]] || args[publisher]="inventree"
|
[[ -n ${args[publisher]:-} ]] || args[publisher]="inventree"
|
||||||
|
|
||||||
# :command.whitelist_filter
|
|
||||||
if [[ ! ${args[source]} =~ ^(stable|master|main)$ ]]; then
|
if [[ ! ${args[source]} =~ ^(stable|master|main)$ ]]; then
|
||||||
printf "%s\n" "source must be one of: stable, master, main" >&2
|
printf "%s\n" "source must be one of: stable, master, main" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -314,17 +287,14 @@ parse_requirements() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# :command.initialize
|
|
||||||
initialize() {
|
initialize() {
|
||||||
version="2.0"
|
version="2.0"
|
||||||
long_usage=''
|
long_usage=''
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# src/initialize.sh
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# :command.run
|
|
||||||
run() {
|
run() {
|
||||||
declare -A args=()
|
declare -A args=()
|
||||||
declare -a other_args=()
|
declare -a other_args=()
|
||||||
|
|||||||
@@ -1,341 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# This script was generated by bashly 0.8.9 (https://bashly.dannyb.co)
|
|
||||||
# Modifying it manually is not recommended
|
|
||||||
|
|
||||||
# :wrapper.bash3_bouncer
|
|
||||||
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
|
|
||||||
printf "bash version 4 or higher is required\n" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# :command.master_script
|
|
||||||
# :command.root_command
|
|
||||||
root_command() {
|
|
||||||
# src/root_command.sh
|
|
||||||
# Settings
|
|
||||||
source_url=${args[source]}
|
|
||||||
publisher=${args[publisher]}
|
|
||||||
# Flags
|
|
||||||
no_call=${args[--no-call]}
|
|
||||||
dry_run=${args[--dry-run]}
|
|
||||||
|
|
||||||
REQS="wget apt-transport-https"
|
|
||||||
|
|
||||||
function do_call() {
|
|
||||||
if [[ $dry_run ]]; then
|
|
||||||
echo -e "### DRY RUN: \n$1"
|
|
||||||
else
|
|
||||||
$1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_distribution {
|
|
||||||
if [ -f /etc/os-release ]; then
|
|
||||||
. /etc/os-release
|
|
||||||
OS=$NAME
|
|
||||||
VER=$VERSION_ID
|
|
||||||
elif type lsb_release >/dev/null 2>&1; then
|
|
||||||
OS=$(lsb_release -si)
|
|
||||||
VER=$(lsb_release -sr)
|
|
||||||
elif [ -f /etc/lsb-release ]; then
|
|
||||||
. /etc/lsb-release
|
|
||||||
OS=$DISTRIB_ID
|
|
||||||
VER=$DISTRIB_RELEASE
|
|
||||||
elif [ -f /etc/debian_version ]; then
|
|
||||||
OS=Debian
|
|
||||||
VER=$(cat /etc/debian_version)
|
|
||||||
elif [ -f /etc/SuSe-release ]; then
|
|
||||||
OS=SEL
|
|
||||||
elif [ -f /etc/redhat-release ]; then
|
|
||||||
OS=RedHat
|
|
||||||
else
|
|
||||||
OS=$(uname -s)
|
|
||||||
VER=$(uname -r)
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "### Installer for InvenTree - source: $publisher/$source_url"
|
|
||||||
|
|
||||||
# Check if os and version is supported
|
|
||||||
get_distribution
|
|
||||||
echo "### Detected distribution: $OS $VER"
|
|
||||||
NOT_SUPPORTED=false
|
|
||||||
case "$OS" in
|
|
||||||
Ubuntu)
|
|
||||||
if [[ $VER != "20.04" ]]; then
|
|
||||||
NOT_SUPPORTED=true
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
Debian | Raspbian)
|
|
||||||
if [[ $VER != "11" ]]; then
|
|
||||||
NOT_SUPPORTED=true
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "### Distribution not supported"
|
|
||||||
NOT_SUPPORTED=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [[ $NOT_SUPPORTED ]]; then
|
|
||||||
echo "This OS is currently not supported"
|
|
||||||
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
|
|
||||||
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
|
|
||||||
echo "If you think this is a bug please file an issue at"
|
|
||||||
echo "https://github.com/inventree/InvenTree/issues/new?template=install.yaml"
|
|
||||||
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "### Installing required packages for download"
|
|
||||||
for pkg in $REQS; do
|
|
||||||
if dpkg-query -W -f'${Status}' "$pkg" 2>/dev/null | grep -q "ok installed"; then
|
|
||||||
true
|
|
||||||
else
|
|
||||||
do_call "sudo apt-get -yqq install $pkg"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "### Adding key and package source"
|
|
||||||
# Add key
|
|
||||||
do_call "wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -"
|
|
||||||
# Add packagelist
|
|
||||||
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${lsb_dist}/${dist_version}.repo"
|
|
||||||
|
|
||||||
echo "### Updateing package lists"
|
|
||||||
do_call "sudo apt-get update"
|
|
||||||
|
|
||||||
# Set up environment for install
|
|
||||||
echo "### Setting installer args"
|
|
||||||
if [[ $no_call ]]; then
|
|
||||||
do_call "export NO_CALL=true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "### Installing InvenTree"
|
|
||||||
do_call "sudo apt-get install inventree -y"
|
|
||||||
|
|
||||||
echo "### Install done!"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# :command.version_command
|
|
||||||
version_command() {
|
|
||||||
echo "$version"
|
|
||||||
}
|
|
||||||
|
|
||||||
# :command.usage
|
|
||||||
install_usage() {
|
|
||||||
if [[ -n $long_usage ]]; then
|
|
||||||
printf "install - Interactive installer for InvenTree\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
else
|
|
||||||
printf "install - Interactive installer for InvenTree\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf "Usage:\n"
|
|
||||||
printf " install [SOURCE] [PUBLISHER] [OPTIONS]\n"
|
|
||||||
printf " install --help | -h\n"
|
|
||||||
printf " install --version | -v\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# :command.long_usage
|
|
||||||
if [[ -n $long_usage ]]; then
|
|
||||||
printf "Options:\n"
|
|
||||||
|
|
||||||
# :command.usage_fixed_flags
|
|
||||||
echo " --help, -h"
|
|
||||||
printf " Show this help\n"
|
|
||||||
echo
|
|
||||||
echo " --version, -v"
|
|
||||||
printf " Show version number\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# :command.usage_flags
|
|
||||||
# :flag.usage
|
|
||||||
echo " --no-call, -n"
|
|
||||||
printf " Do not call outside APIs (only functionally needed)\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# :flag.usage
|
|
||||||
echo " --dry-run, -d"
|
|
||||||
printf " Dry run (do not install anything)\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# :command.usage_args
|
|
||||||
printf "Arguments:\n"
|
|
||||||
|
|
||||||
# :argument.usage
|
|
||||||
echo " SOURCE"
|
|
||||||
printf " Package source that should be used\n"
|
|
||||||
printf " Allowed: stable, master, main\n"
|
|
||||||
printf " Default: stable\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# :argument.usage
|
|
||||||
echo " PUBLISHER"
|
|
||||||
printf " Publisher that should be used\n"
|
|
||||||
printf " Default: inventree\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# :command.usage_examples
|
|
||||||
printf "Examples:\n"
|
|
||||||
printf " install\n"
|
|
||||||
printf " install master --no-call\n"
|
|
||||||
printf " install master matmair --dry-run\n"
|
|
||||||
echo
|
|
||||||
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# :command.normalize_input
|
|
||||||
normalize_input() {
|
|
||||||
local arg flags
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
arg="$1"
|
|
||||||
if [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
|
|
||||||
input+=("${BASH_REMATCH[1]}")
|
|
||||||
input+=("${BASH_REMATCH[2]}")
|
|
||||||
elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
|
|
||||||
input+=("${BASH_REMATCH[1]}")
|
|
||||||
input+=("${BASH_REMATCH[2]}")
|
|
||||||
elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then
|
|
||||||
flags="${BASH_REMATCH[1]}"
|
|
||||||
for (( i=0 ; i < ${#flags} ; i++ )); do
|
|
||||||
input+=("-${flags:i:1}")
|
|
||||||
done
|
|
||||||
else
|
|
||||||
input+=("$arg")
|
|
||||||
fi
|
|
||||||
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
# :command.inspect_args
|
|
||||||
inspect_args() {
|
|
||||||
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
|
|
||||||
if (( ${#args[@]} )); then
|
|
||||||
echo args:
|
|
||||||
for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
|
|
||||||
else
|
|
||||||
echo args: none
|
|
||||||
fi
|
|
||||||
|
|
||||||
if (( ${#other_args[@]} )); then
|
|
||||||
echo
|
|
||||||
echo other_args:
|
|
||||||
echo "- \${other_args[*]} = ${other_args[*]}"
|
|
||||||
for i in "${!other_args[@]}"; do
|
|
||||||
echo "- \${other_args[$i]} = ${other_args[$i]}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# :command.command_functions
|
|
||||||
|
|
||||||
# :command.parse_requirements
|
|
||||||
parse_requirements() {
|
|
||||||
# :command.fixed_flags_filter
|
|
||||||
case "${1:-}" in
|
|
||||||
--version | -v )
|
|
||||||
version_command
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
|
|
||||||
--help | -h )
|
|
||||||
long_usage=yes
|
|
||||||
install_usage
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
||||||
|
|
||||||
# :command.command_filter
|
|
||||||
action="root"
|
|
||||||
|
|
||||||
# :command.parse_requirements_while
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
key="$1"
|
|
||||||
case "$key" in
|
|
||||||
# :flag.case
|
|
||||||
--no-call | -n )
|
|
||||||
|
|
||||||
# :flag.case_no_arg
|
|
||||||
args[--no-call]=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
# :flag.case
|
|
||||||
--dry-run | -d )
|
|
||||||
|
|
||||||
# :flag.case_no_arg
|
|
||||||
args[--dry-run]=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
-?* )
|
|
||||||
printf "invalid option: %s\n" "$key" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
* )
|
|
||||||
# :command.parse_requirements_case
|
|
||||||
# :command.parse_requirements_case_simple
|
|
||||||
if [[ -z ${args[source]+x} ]]; then
|
|
||||||
|
|
||||||
args[source]=$1
|
|
||||||
shift
|
|
||||||
elif [[ -z ${args[publisher]+x} ]]; then
|
|
||||||
|
|
||||||
args[publisher]=$1
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
printf "invalid argument: %s\n" "$key" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# :command.default_assignments
|
|
||||||
[[ -n ${args[source]:-} ]] || args[source]="stable"
|
|
||||||
[[ -n ${args[publisher]:-} ]] || args[publisher]="inventree"
|
|
||||||
|
|
||||||
# :command.whitelist_filter
|
|
||||||
if [[ ! ${args[source]} =~ ^(stable|master|main)$ ]]; then
|
|
||||||
printf "%s\n" "source must be one of: stable, master, main" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# :command.initialize
|
|
||||||
initialize() {
|
|
||||||
version="2.0"
|
|
||||||
long_usage=''
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# src/initialize.sh
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# :command.run
|
|
||||||
run() {
|
|
||||||
declare -A args=()
|
|
||||||
declare -a other_args=()
|
|
||||||
declare -a input=()
|
|
||||||
normalize_input "$@"
|
|
||||||
parse_requirements "${input[@]}"
|
|
||||||
|
|
||||||
if [[ $action == "root" ]]; then
|
|
||||||
root_command
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize
|
|
||||||
run "$@"
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# All settings are optional (with their default values provided below), and
|
||||||
|
# can also be set with an environment variable with the same name, capitalized
|
||||||
|
# and prefixed by `BASHLY_` - for example: BASHLY_SOURCE_DIR
|
||||||
|
#
|
||||||
|
# When setting environment variables, you can use:
|
||||||
|
# - "0", "false" or "no" to represent false
|
||||||
|
# - "1", "true" or "yes" to represent true
|
||||||
|
|
||||||
|
# The path containing the bashly configuration and source files
|
||||||
|
source_dir: src
|
||||||
|
|
||||||
|
# The path to use for creating the bash script
|
||||||
|
target_dir: ..
|
||||||
|
|
||||||
|
# The path to use for upgrading library files, relative to the source dir
|
||||||
|
lib_dir: lib
|
||||||
|
|
||||||
|
# When true, enable bash strict mode (set -euo pipefail)
|
||||||
|
strict: false
|
||||||
|
|
||||||
|
# When true, the generated script will use tab indentation instead of spaces
|
||||||
|
# (every 2 leading spaces will be converted to a tab character)
|
||||||
|
tab_indent: false
|
||||||
|
|
||||||
|
# When true, the generated script will consider any argument in the form of
|
||||||
|
# `-abc` as if it is `-a -b -c`.
|
||||||
|
compact_short_flags: true
|
||||||
|
|
||||||
|
# Set to 'production' or 'development':
|
||||||
|
# - production generate a smaller script, without file markers
|
||||||
|
# - development generate with file markers
|
||||||
|
env: production
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: install
|
name: install.sh
|
||||||
help: Interactive installer for InvenTree
|
help: Interactive installer for InvenTree
|
||||||
version: 2.0
|
version: 2.0
|
||||||
|
|
||||||
|
|||||||
@@ -45,25 +45,26 @@ echo "### Installer for InvenTree - source: $publisher/$source_url"
|
|||||||
# Check if os and version is supported
|
# Check if os and version is supported
|
||||||
get_distribution
|
get_distribution
|
||||||
echo "### Detected distribution: $OS $VER"
|
echo "### Detected distribution: $OS $VER"
|
||||||
NOT_SUPPORTED=false
|
SUPPORTED=true
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
Ubuntu)
|
Ubuntu)
|
||||||
if [[ $VER != "20.04" ]]; then
|
if [[ $VER != "20.04" ]]; then
|
||||||
NOT_SUPPORTED=true
|
SUPPORTED=false
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
Debian | Raspbian)
|
"Debian GNU/Linux" | Raspbian)
|
||||||
if [[ $VER != "11" ]]; then
|
if [[ $VER != "11" ]]; then
|
||||||
NOT_SUPPORTED=true
|
SUPPORTED=false
|
||||||
fi
|
fi
|
||||||
|
OS=Debian
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "### Distribution not supported"
|
echo "### Distribution not supported"
|
||||||
NOT_SUPPORTED=true
|
SUPPORTED=false
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ $NOT_SUPPORTED ]]; then
|
if [[ $SUPPORTED != "true" ]]; then
|
||||||
echo "This OS is currently not supported"
|
echo "This OS is currently not supported"
|
||||||
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
|
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
|
||||||
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
|
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
|
||||||
@@ -82,11 +83,10 @@ for pkg in $REQS; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "### Adding key and package source"
|
echo "### Getting and adding key"
|
||||||
# Add key
|
wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -
|
||||||
do_call "wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -"
|
echo "### Adding package source"
|
||||||
# Add packagelist
|
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${OS,,}/${VER}.repo"
|
||||||
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${lsb_dist}/${dist_version}.repo"
|
|
||||||
|
|
||||||
echo "### Updateing package lists"
|
echo "### Updateing package lists"
|
||||||
do_call "sudo apt-get update"
|
do_call "sudo apt-get update"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ function detect_envs() {
|
|||||||
|
|
||||||
echo "# Setting base environment variables"
|
echo "# Setting base environment variables"
|
||||||
|
|
||||||
export INVENTREE_CONFIG_FILE=${CONF_DIR}/config.yaml
|
export INVENTREE_CONFIG_FILE=${INVENTREE_CONFIG_FILE:-${CONF_DIR}/config.yaml}
|
||||||
|
|
||||||
if test -f "${INVENTREE_CONFIG_FILE}"; then
|
if test -f "${INVENTREE_CONFIG_FILE}"; then
|
||||||
echo "# Using existing config file: ${INVENTREE_CONFIG_FILE}"
|
echo "# Using existing config file: ${INVENTREE_CONFIG_FILE}"
|
||||||
@@ -93,22 +93,22 @@ function detect_envs() {
|
|||||||
pip install jc -q
|
pip install jc -q
|
||||||
|
|
||||||
# Load config
|
# Load config
|
||||||
local conf=$(cat ${INVENTREE_CONFIG_FILE} | jc --yaml)
|
local CONF=$(cat ${INVENTREE_CONFIG_FILE} | jc --yaml)
|
||||||
|
|
||||||
# Parse the config file
|
# Parse the config file
|
||||||
export INVENTREE_MEDIA_ROOT=$conf | jq '.[].media_root'
|
export INVENTREE_MEDIA_ROOT=$(jq -r '.[].media_root' <<< ${CONF})
|
||||||
export INVENTREE_STATIC_ROOT=$conf | jq '.[].static_root'
|
export INVENTREE_STATIC_ROOT=$(jq -r '.[].static_root' <<< ${CONF})
|
||||||
export INVENTREE_BACKUP_DIR=$conf | jq '.[].backup_dir'
|
export INVENTREE_BACKUP_DIR=$(jq -r '.[].backup_dir' <<< ${CONF})
|
||||||
export INVENTREE_PLUGINS_ENABLED=$conf | jq '.[].plugins_enabled'
|
export INVENTREE_PLUGINS_ENABLED=$(jq -r '.[].plugins_enabled' <<< ${CONF})
|
||||||
export INVENTREE_PLUGIN_FILE=$conf | jq '.[].plugin_file'
|
export INVENTREE_PLUGIN_FILE=$(jq -r '.[].plugin_file' <<< ${CONF})
|
||||||
export INVENTREE_SECRET_KEY_FILE=$conf | jq '.[].secret_key_file'
|
export INVENTREE_SECRET_KEY_FILE=$(jq -r '.[].secret_key_file' <<< ${CONF})
|
||||||
|
|
||||||
export INVENTREE_DB_ENGINE=$conf | jq '.[].database.ENGINE'
|
export INVENTREE_DB_ENGINE=$(jq -r '.[].database.ENGINE' <<< ${CONF})
|
||||||
export INVENTREE_DB_NAME=$conf | jq '.[].database.NAME'
|
export INVENTREE_DB_NAME=$(jq -r '.[].database.NAME' <<< ${CONF})
|
||||||
export INVENTREE_DB_USER=$conf | jq '.[].database.USER'
|
export INVENTREE_DB_USER=$(jq -r '.[].database.USER' <<< ${CONF})
|
||||||
export INVENTREE_DB_PASSWORD=$conf | jq '.[].database.PASSWORD'
|
export INVENTREE_DB_PASSWORD=$(jq -r '.[].database.PASSWORD' <<< ${CONF})
|
||||||
export INVENTREE_DB_HOST=$conf | jq '.[].database.HOST'
|
export INVENTREE_DB_HOST=$(jq -r '.[].database.HOST' <<< ${CONF})
|
||||||
export INVENTREE_DB_PORT=$conf | jq '.[].database.PORT'
|
export INVENTREE_DB_PORT=$(jq -r '.[].database.PORT' <<< ${CONF})
|
||||||
else
|
else
|
||||||
echo "# No config file found: ${INVENTREE_CONFIG_FILE}, using envs or defaults"
|
echo "# No config file found: ${INVENTREE_CONFIG_FILE}, using envs or defaults"
|
||||||
|
|
||||||
@@ -160,7 +160,8 @@ function create_initscripts() {
|
|||||||
echo "# python enviroment already present - skipping"
|
echo "# python enviroment already present - skipping"
|
||||||
else
|
else
|
||||||
echo "# Setting up python enviroment"
|
echo "# Setting up python enviroment"
|
||||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && python3 -m venv env && pip install invoke"
|
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && ${SETUP_PYTHON} -m venv env"
|
||||||
|
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && env/bin/pip install invoke wheel"
|
||||||
|
|
||||||
if [ -n "${SETUP_EXTRA_PIP}" ]; then
|
if [ -n "${SETUP_EXTRA_PIP}" ]; then
|
||||||
echo "# Installing extra pip packages"
|
echo "# Installing extra pip packages"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ PATH=${APP_HOME}/env/bin:${APP_HOME}/:/sbin:/bin:/usr/sbin:/usr/bin:
|
|||||||
. ${APP_HOME}/contrib/packager.io/functions.sh
|
. ${APP_HOME}/contrib/packager.io/functions.sh
|
||||||
|
|
||||||
# Envs that should be passed to setup commands
|
# Envs that should be passed to setup commands
|
||||||
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP
|
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON
|
||||||
|
|
||||||
# Get the envs
|
# Get the envs
|
||||||
detect_local_env
|
detect_local_env
|
||||||
@@ -23,8 +23,10 @@ export DATA_DIR=${APP_HOME}/data
|
|||||||
export SETUP_NGINX_FILE=${SETUP_NGINX_FILE:-/etc/nginx/sites-enabled/inventree.conf}
|
export SETUP_NGINX_FILE=${SETUP_NGINX_FILE:-/etc/nginx/sites-enabled/inventree.conf}
|
||||||
export SETUP_ADMIN_PASSWORD_FILE=${CONF_DIR}/admin_password.txt
|
export SETUP_ADMIN_PASSWORD_FILE=${CONF_DIR}/admin_password.txt
|
||||||
export SETUP_NO_CALLS=${SETUP_NO_CALLS:-false}
|
export SETUP_NO_CALLS=${SETUP_NO_CALLS:-false}
|
||||||
|
export SETUP_PYTHON=${SETUP_PYTHON:-python3}
|
||||||
# SETUP_DEBUG can be set to get debug info
|
# SETUP_DEBUG can be set to get debug info
|
||||||
# SETUP_EXTRA_PIP can be set to install extra pip packages
|
# SETUP_EXTRA_PIP can be set to install extra pip packages
|
||||||
|
# SETUP_PYTHON can be set to use a different python version
|
||||||
|
|
||||||
# get base info
|
# get base info
|
||||||
detect_envs
|
detect_envs
|
||||||
|
|||||||
Reference in New Issue
Block a user