Compare commits
1 Commits
master
...
2d83c9ceec
Author | SHA1 | Date | |
---|---|---|---|
2d83c9ceec |
@@ -1 +0,0 @@
|
|||||||
start_server.sh
|
|
@@ -1,6 +0,0 @@
|
|||||||
FROM alpine:latest
|
|
||||||
RUN apk add --no-cache python3 py3-pip python3-dev py3-setuptools gcc python3-dev jpeg-dev zlib-dev musl-dev py3-gunicorn
|
|
||||||
COPY . /home/shimatta/kenkyusho
|
|
||||||
WORKDIR /home/shimatta/kenkyusho
|
|
||||||
RUN python3 -m venv /home/shimatta/kenkyusho/.venv && . /home/shimatta/kenkyusho/.venv/bin/activate && pip install -r requirements.txt
|
|
||||||
ENTRYPOINT ["/home/shimatta/kenkyusho/entrypoint.sh"]
|
|
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
source /home/shimatta/kenkyusho/.venv/bin/activate
|
|
||||||
cd /home/shimatta/kenkyusho/shimatta_kenkyusho
|
|
||||||
python manage.py migrate --settings shimatta_kenkyusho.settings_production
|
|
||||||
python manage.py collectstatic --settings shimatta_kenkyusho.settings_production --noinput
|
|
||||||
gunicorn -w 4 shimatta_kenkyusho.wsgi:application
|
|
@@ -14,6 +14,7 @@ lazy-object-proxy==1.6.0
|
|||||||
MarkupSafe==2.0.1
|
MarkupSafe==2.0.1
|
||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
Pillow==8.3.1
|
Pillow==8.3.1
|
||||||
|
psycopg2==2.9.1
|
||||||
pylint==2.9.6
|
pylint==2.9.6
|
||||||
pytz==2021.1
|
pytz==2021.1
|
||||||
qrcode==7.2
|
qrcode==7.2
|
||||||
@@ -22,5 +23,3 @@ six==1.16.0
|
|||||||
sqlparse==0.4.1
|
sqlparse==0.4.1
|
||||||
toml==0.10.2
|
toml==0.10.2
|
||||||
wrapt==1.12.1
|
wrapt==1.12.1
|
||||||
psycopg2-binary==2.9.9
|
|
||||||
gunicorn==21.2.0
|
|
||||||
|
@@ -50,9 +50,8 @@ class PartsComponentViewSet(viewsets.ModelViewSet):
|
|||||||
queryset = parts_models.Component.objects.all()
|
queryset = parts_models.Component.objects.all()
|
||||||
serializer_class = ComponentSerializer
|
serializer_class = ComponentSerializer
|
||||||
permission_classes = [permissions.DjangoModelPermissions]
|
permission_classes = [permissions.DjangoModelPermissions]
|
||||||
filter_backends = [filters.SearchFilter, django_filters.rest_framework.DjangoFilterBackend]
|
filter_backends = [filters.SearchFilter]
|
||||||
search_fields = ['id', 'name', 'package__name', 'manufacturer__name']
|
search_fields = ['id', 'name', 'package__name', 'manufacturer__name']
|
||||||
filterset_fields = ['id', 'name']
|
|
||||||
|
|
||||||
class PartsComponentTypeViewSet(viewsets.ModelViewSet):
|
class PartsComponentTypeViewSet(viewsets.ModelViewSet):
|
||||||
queryset = parts_models.ComponentType.objects.all()
|
queryset = parts_models.ComponentType.objects.all()
|
||||||
|
@@ -276,6 +276,29 @@ class ComponentParameterSearchForm(forms.Form):
|
|||||||
Column('value')
|
Column('value')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
parameter = cleaned_data.get('parameter')
|
||||||
|
value = cleaned_data.get('value')
|
||||||
|
|
||||||
|
if value != '' or value != None:
|
||||||
|
value = value.strip()
|
||||||
|
|
||||||
|
if value == '' or value == None:
|
||||||
|
cleaned_data['value'] = None
|
||||||
|
value = None
|
||||||
|
|
||||||
|
if parameter and value is not None and value != '':
|
||||||
|
if parameter.parameter_type != 'F':
|
||||||
|
try:
|
||||||
|
cleaned_data['value'] = EngineeringNumberConverter.engineering_to_number(value)
|
||||||
|
except:
|
||||||
|
raise ValidationError('Cannot convert value to number')
|
||||||
|
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class ComponentParameterCreateForm(forms.Form):
|
class ComponentParameterCreateForm(forms.Form):
|
||||||
parameter_type = AutocompleteForeingKeyField(required=True, foreign_model=parts_models.ComponentParameterType, api_search_url='componentparametertype-list', image_field_name=None, name_field_name='descriptive_name')
|
parameter_type = AutocompleteForeingKeyField(required=True, foreign_model=parts_models.ComponentParameterType, api_search_url='componentparametertype-list', image_field_name=None, name_field_name='descriptive_name')
|
||||||
value = forms.CharField(required=True, max_length=256)
|
value = forms.CharField(required=True, max_length=256)
|
||||||
|
@@ -1,59 +0,0 @@
|
|||||||
from django.core.management.base import BaseCommand
|
|
||||||
from parts.models import Component, Package, Distributor, Manufacturer
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = 'Migrate all media files to the current folder structure'
|
|
||||||
|
|
||||||
def move_files_of_model(self, queryset):
|
|
||||||
for comp in queryset:
|
|
||||||
img_path = comp.image.name
|
|
||||||
img_path = os.path.normpath(img_path)
|
|
||||||
path_components = img_path.split(os.sep)
|
|
||||||
|
|
||||||
if len(path_components) <= 2:
|
|
||||||
self.stdout.write(f'Legacy path found: {img_path}. Will be moved')
|
|
||||||
full_path_components = os.path.normpath(comp.image.path).split(os.sep)
|
|
||||||
fname = full_path_components[-1]
|
|
||||||
path_elem_count = len(full_path_components)
|
|
||||||
full_path_components.insert(path_elem_count-1, str(fname[1]))
|
|
||||||
full_path_components.insert(path_elem_count-1, str(fname[0]))
|
|
||||||
dest_path = os.sep.join(full_path_components)
|
|
||||||
|
|
||||||
# Move file
|
|
||||||
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
|
|
||||||
shutil.move(comp.image.path, dest_path)
|
|
||||||
|
|
||||||
# Update model
|
|
||||||
new_rel_path_comps = path_components
|
|
||||||
l = len(new_rel_path_comps)
|
|
||||||
new_rel_path_comps.insert(l-1, str(fname[1]))
|
|
||||||
new_rel_path_comps.insert(l-1, str(fname[0]))
|
|
||||||
new_name = os.sep.join(new_rel_path_comps)
|
|
||||||
self.stdout.write(f'New location: {dest_path}, new name: {new_name}')
|
|
||||||
comp.image.name = new_name
|
|
||||||
comp.save()
|
|
||||||
|
|
||||||
def handle(self, *args, **kwargs):
|
|
||||||
|
|
||||||
self.stdout.write('Querying components...')
|
|
||||||
components = Component.objects.exclude(image='')
|
|
||||||
self.stdout.write(f'Count of components with images: {components.count()}');
|
|
||||||
self.move_files_of_model(components)
|
|
||||||
|
|
||||||
self.stdout.write('Querying packages...')
|
|
||||||
pkgs = Package.objects.exclude(image='')
|
|
||||||
self.stdout.write(f'Count of components with images: {pkgs.count()}');
|
|
||||||
self.move_files_of_model(pkgs)
|
|
||||||
|
|
||||||
self.stdout.write('Querying manufacturers...')
|
|
||||||
manufacturers = Manufacturer.objects.exclude(image='')
|
|
||||||
self.stdout.write(f'Count of components with images: {manufacturers.count()}');
|
|
||||||
self.move_files_of_model(manufacturers)
|
|
||||||
|
|
||||||
self.stdout.write('Querying distributors...')
|
|
||||||
distris = Distributor.objects.exclude(image='')
|
|
||||||
self.stdout.write(f'Count of components with images: {distris.count()}');
|
|
||||||
self.move_files_of_model(distris)
|
|
||||||
|
|
@@ -23,7 +23,7 @@ from django.db.models.functions import Lower
|
|||||||
from django.forms import formset_factory
|
from django.forms import formset_factory
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
ParameterSearchFormSet = formset_factory(ComponentParameterSearchForm, extra=1)
|
ParameterSearchFormSet = formset_factory(ComponentParameterSearchForm, extra=2)
|
||||||
|
|
||||||
class QrSearchForm(forms.Form):
|
class QrSearchForm(forms.Form):
|
||||||
my_qr_validator = QrCodeValidator()
|
my_qr_validator = QrCodeValidator()
|
||||||
@@ -181,6 +181,17 @@ class ComponentView(LoginRequiredMixin, BaseTemplateMixin, TemplateView):
|
|||||||
queryset = queryset.filter(manufacturer=cleaned_data['manufacturer'])
|
queryset = queryset.filter(manufacturer=cleaned_data['manufacturer'])
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
def filter_queryset_with_parameters(self, queryset, parameter, value):
|
||||||
|
if parameter and (value is None or value == ''):
|
||||||
|
return queryset.filter(Q(componentparameter__parameter_type=parameter))
|
||||||
|
elif parameter and value is not None:
|
||||||
|
if parameter.parameter_type == 'F':
|
||||||
|
return queryset.filter(Q(componentparameter__text_value__icontains=value))
|
||||||
|
else:
|
||||||
|
return queryset.filter(Q(componentparameter__value=value))
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
def get_context_data_int(self, advanced_search, parameter_formset : ParameterSearchFormSet, **kwargs):
|
def get_context_data_int(self, advanced_search, parameter_formset : ParameterSearchFormSet, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
@@ -198,7 +209,12 @@ class ComponentView(LoginRequiredMixin, BaseTemplateMixin, TemplateView):
|
|||||||
|
|
||||||
if parameter_formset.is_valid():
|
if parameter_formset.is_valid():
|
||||||
# Process parameters
|
# Process parameters
|
||||||
pass
|
for f in parameter_formset:
|
||||||
|
# If the form is valid and has changed compared to its initial empty state
|
||||||
|
if f.is_valid() and f.has_changed():
|
||||||
|
print(f.cleaned_data)
|
||||||
|
paginator_queryset = self.filter_queryset_with_parameters(paginator_queryset, f.cleaned_data['parameter'], f.cleaned_data['value'])
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
search = self.request.GET.get('search', default=None)
|
search = self.request.GET.get('search', default=None)
|
||||||
@@ -557,9 +573,10 @@ class StockViewDetail(LoginRequiredMixin, BaseTemplateMixin, DetailView):
|
|||||||
if edit_form.is_valid():
|
if edit_form.is_valid():
|
||||||
edit_form.save()
|
edit_form.save()
|
||||||
else:
|
else:
|
||||||
pass # Todo: Handle error
|
pass
|
||||||
|
|
||||||
context = self.get_context_data(**kwargs)
|
context = self.get_context_data(**kwargs)
|
||||||
|
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
||||||
def handle_amount_change_post(self, request, increase, **kwargs):
|
def handle_amount_change_post(self, request, increase, **kwargs):
|
||||||
|
@@ -138,7 +138,6 @@ DATABASES = {
|
|||||||
'USER': db_user,
|
'USER': db_user,
|
||||||
'PASSWORD': db_pw,
|
'PASSWORD': db_pw,
|
||||||
'HOST': get_env_value('DJANGO_POSTGRESQL_SOCKET'),
|
'HOST': get_env_value('DJANGO_POSTGRESQL_SOCKET'),
|
||||||
'PORT': get_env_value('DJANGO_POSTGRESQL_PORT'),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +229,6 @@ CRISPY_TEMPLATE_PACK = "bootstrap5"
|
|||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
CSRF_COOKIE_SECURE = True
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
SECURE_SSL_REDIRECT = False
|
SECURE_SSL_REDIRECT = True
|
||||||
|
|
||||||
SECURE_HSTS_SECONDS = get_env_value('DJANGO_SECURE_HSTS_SECONDS', default=120)
|
SECURE_HSTS_SECONDS = get_env_value('DJANGO_SECURE_HSTS_SECONDS', default=120)
|
@@ -6,13 +6,8 @@ from django.utils.deconstruct import deconstructible
|
|||||||
@deconstructible
|
@deconstructible
|
||||||
class RandomFileName(object):
|
class RandomFileName(object):
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
self.path = os.path.join(path, "%s/%s/%s%s")
|
self.path = os.path.join(path, "%s%s")
|
||||||
|
|
||||||
def __call__(self, _, filename):
|
def __call__(self, _, filename):
|
||||||
extension = os.path.splitext(filename)[1]
|
extension = os.path.splitext(filename)[1]
|
||||||
file_uuid = uuid.uuid4()
|
return self.path % (uuid.uuid4(), extension)
|
||||||
uuid_str = str(file_uuid)
|
|
||||||
first_char = uuid_str[0]
|
|
||||||
second_char = uuid_str[1]
|
|
||||||
|
|
||||||
return self.path % (first_char, second_char, file_uuid, extension)
|
|
@@ -31,6 +31,9 @@
|
|||||||
<input type="submit" name="submit-advanced-search" value="Search" class="btn btn-success">
|
<input type="submit" name="submit-advanced-search" value="Search" class="btn btn-success">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<template id="advanced-search-parameter-template">
|
||||||
|
{% crispy advanced_search_param_formset.empty_form %}
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group mb-3">
|
<div class="list-group mb-3">
|
||||||
{% for comp in components %}
|
{% for comp in components %}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
podman run -it -e DJANGO_SECRET_KEY=<secret_key> -e DJANGO_ALLOWED_HOST=parts.shimatta.net -e DJANGO_STATIC_ROOT=/var/static -e DJANGO_MEDIA_URL=media -e DJANGO_MEDIA_ROOT=/var/media -e DJANGO_POSTGRESQL_SOCKET=host.docker.internal -e DJANGO_POSTGRESQL_PORT=2345 -e DJANGO_POSTGRESQL_USER=<db_user> -e DJANGO_POSTGRESQL_PW=<db_pass> -v /var/parts/static:/var/static -v /var/parts/media:/var/media -p 8000:8000 --entrypoint /bin/sh localhost/kenkyusho:0.1
|
|
Reference in New Issue
Block a user