Merge pull request 'feature/thumbnails' (#12) from feature/thumbnails into main
Reviewed-on: #12feature/peertube_embedded 0.1.0
commit
9200e554be
|
@ -0,0 +1,21 @@
|
|||
steps:
|
||||
build:
|
||||
image: docker:24.0.6
|
||||
secrets: []
|
||||
commands:
|
||||
- docker compose -f artel/docker-compose-test.yml build
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
when:
|
||||
event: pull_request
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
test:
|
||||
image: docker:24.0.6
|
||||
secrets: []
|
||||
commands:
|
||||
- docker compose -f artel/docker-compose-test.yml run --rm test_comfy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
when:
|
||||
event: pull_request
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
|
@ -0,0 +1,3 @@
|
|||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
|
@ -0,0 +1,17 @@
|
|||
import os
|
||||
|
||||
from celery import Celery
|
||||
|
||||
# Set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'artel.settings.production')
|
||||
|
||||
app = Celery('artel')
|
||||
|
||||
# Using a string here means the worker doesn't have to serialize
|
||||
# the configuration object to child processes.
|
||||
# - namespace='CELERY' means all celery-related configuration keys
|
||||
# should have a `CELERY_` prefix.
|
||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||
|
||||
# Load task modules from all registered Django apps.
|
||||
app.autodiscover_tasks()
|
|
@ -65,6 +65,9 @@ INSTALLED_APPS = [
|
|||
"django.contrib.staticfiles",
|
||||
"rest_framework",
|
||||
"phonenumber_field",
|
||||
"django_celery_results",
|
||||
"django_celery_beat",
|
||||
"easy_thumbnails",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -214,6 +217,29 @@ EMAIL_PORT = os.environ.get('EMAIL_PORT', 587)
|
|||
EMAIL_USE_TLS = True
|
||||
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'artel-sklep@tepewu.pl')
|
||||
|
||||
# CELERY settings
|
||||
CELERY_RESULT_BACKEND = os.environ.get("CELERY_RESULT_BACKEND")
|
||||
CELERY_CACHE_BACKEND = os.environ.get("CELERY_CACHE_BACKEND")
|
||||
CELERY_TIMEZONE = os.environ.get("CELERY_TIMEZONE")
|
||||
CELERY_TASK_TRACK_STARTED = os.environ.get("CELERY_TASK_TRACK_STARTED")
|
||||
CELERY_TASK_TIME_LIMIT = os.environ.get("CELERY_TASK_TIME_LIMIT")
|
||||
# CELERY_RESULT_BACKEND_DB = f'db+mysql+pymysql://{os.environ.get("MYSQL_USER")}:{os.environ.get("MYSQL_PASSWORD")}@db/{os.environ.get("MYSQL_DATABASE")}'
|
||||
CELERY_BROKER_URL = f'amqp://{os.environ.get("RABBITMQ_DEFAULT_USER")}:{os.environ.get("RABBITMQ_DEFAULT_PASS")}@rabbit//'
|
||||
CELERY_TASK_RESULT_EXPIRES = os.environ.get("CELERY_TASK_RESULT_EXPIRES")
|
||||
CELERY_ACCEPT_CONTENT = ['pickle'] #add this to your env
|
||||
|
||||
# EASY_THUMBNAILS settings
|
||||
|
||||
THUMBNAIL_DEFAULT_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
THUMBNAIL_ALIASES = {
|
||||
'': {
|
||||
'image_40_60': {'size': (40, 60), 'crop': True},
|
||||
'image_60_90': {'size': (60, 90), 'crop': True},
|
||||
'image_80_120': {'size': (80, 120), 'crop': True},
|
||||
'image_120_180': {'size': (120, 180), 'crop': True},
|
||||
'image_160_240': {'size': (160, 240), 'crop': True},
|
||||
},
|
||||
}
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
from artel.settings.base import *
|
||||
|
||||
# SECURITY WARNING: define the correct hosts in production!
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = "smtp-server"
|
||||
EMAIL_HOST_USER = None
|
||||
EMAIL_HOST_PASSWORD = None
|
||||
EMAIL_PORT = 1025
|
||||
EMAIL_USE_TLS = False
|
||||
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'mtyton@tepewu.pl')
|
|
@ -0,0 +1,20 @@
|
|||
from .base import *
|
||||
|
||||
# SECURITY WARNING: define the correct hosts in production!
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
SECRET_KEY = "test"
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = "smtp-server"
|
||||
EMAIL_HOST_USER = None
|
||||
EMAIL_HOST_PASSWORD = None
|
||||
EMAIL_PORT = 1025
|
||||
EMAIL_USE_TLS = False
|
||||
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'mtyton@tepewu.pl')
|
||||
|
||||
|
||||
try:
|
||||
from .local import *
|
||||
except ImportError:
|
||||
pass
|
|
@ -0,0 +1,19 @@
|
|||
import celery
|
||||
import logging
|
||||
|
||||
from easy_thumbnails.files import generate_all_aliases
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@celery.shared_task(name="generate_thumbnails")
|
||||
def generate_thumbnails(model, pk, field):
|
||||
try:
|
||||
instance = model._default_manager.get(pk=pk)
|
||||
fieldfile = getattr(instance, field)
|
||||
generate_all_aliases(fieldfile, include_global=True)
|
||||
return {"status": True}
|
||||
except Exception as e:
|
||||
logger.exception("An error occurred while generating thumbnails.")
|
||||
return {"status": False, "error": str(e)}
|
|
@ -4,14 +4,18 @@ services:
|
|||
image: postgres
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_ROOT_PASSWORD
|
||||
- POSTGRES_USER
|
||||
- POSTGRES_PASSWORD
|
||||
- POSTGRES_DB
|
||||
volumes:
|
||||
- ../postgres/:/var/lib/postgresql
|
||||
env_file:
|
||||
- .env
|
||||
- POSTGRES_ROOT_PASSWORD=password
|
||||
- POSTGRES_USER=comfy
|
||||
- POSTGRES_PASSWORD=password
|
||||
- POSTGRES_DB=comfy_shop
|
||||
|
||||
test_rabbit:
|
||||
hostname: rabbit
|
||||
image: rabbitmq:3.6.0
|
||||
environment:
|
||||
- RABBITMQ_DEFAULT_USER=rabbitmq
|
||||
- RABBITMQ_DEFAULT_PASS=rabbitmq
|
||||
|
||||
test_comfy:
|
||||
depends_on:
|
||||
- test_db
|
||||
|
@ -19,12 +23,38 @@ services:
|
|||
dockerfile: Dockerfile.local
|
||||
context: ./
|
||||
user: "${UID}:${GID}"
|
||||
volumes:
|
||||
- ./:/app
|
||||
environment:
|
||||
- SECRET_KEY
|
||||
- DATABASE_URL
|
||||
env_file:
|
||||
- .env
|
||||
- SECRET_KEY=RandomKey
|
||||
- DATABASE_URL=postgres://comfy:password@test_db/comfy_shop
|
||||
- DJANGO_SETTINGS_MODULE=artel.settings.tests
|
||||
- RABBITMQ_DEFAULT_USER=rabbitmq
|
||||
- RABBITMQ_DEFAULT_PASS=rabbitmq
|
||||
command:
|
||||
python manage.py test --noinput
|
||||
|
||||
test_beat:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
command: celery -A artel beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
|
||||
environment:
|
||||
- SECRET_KEY=RandomKey
|
||||
- DATABASE_URL=postgres://comfy:password@test_db/comfy_shop
|
||||
- DJANGO_SETTINGS_MODULE=artel.settings.tests
|
||||
depends_on:
|
||||
- test_comfy
|
||||
- test_rabbit
|
||||
|
||||
test_worker:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
command: celery -A artel worker -l info
|
||||
environment:
|
||||
- SECRET_KEY=RandomKey
|
||||
- DATABASE_URL=postgres://comfy:password@test_db/comfy_shop
|
||||
- DJANGO_SETTINGS_MODULE=artel.settings.tests
|
||||
depends_on:
|
||||
- test_comfy
|
||||
- test_rabbit
|
||||
- test_beat
|
|
@ -1,10 +1,35 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
|
||||
db:
|
||||
image: postgres
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_ROOT_PASSWORD
|
||||
- POSTGRES_USER
|
||||
- POSTGRES_PASSWORD
|
||||
- POSTGRES_DB
|
||||
volumes:
|
||||
- ../postgres/:/var/lib/postgresql
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
rabbit:
|
||||
hostname: rabbit
|
||||
image: rabbitmq:3.6.0
|
||||
environment:
|
||||
- RABBITMQ_DEFAULT_USER
|
||||
- RABBITMQ_DEFAULT_PASS
|
||||
ports:
|
||||
- "5672:5672" # We forward this port because it's useful for debugging
|
||||
- "15672:15672" # Here, we can access RabbitMQ management plugin
|
||||
|
||||
smtp-server:
|
||||
image: mailhog/mailhog
|
||||
ports:
|
||||
- "1025:1025"
|
||||
- "8025:8025"
|
||||
- "8025:8025"
|
||||
|
||||
comfy:
|
||||
restart: always
|
||||
depends_on:
|
||||
|
@ -26,18 +51,40 @@ services:
|
|||
- .env
|
||||
stdin_open: true
|
||||
tty: true
|
||||
db:
|
||||
image: postgres
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_ROOT_PASSWORD
|
||||
- POSTGRES_USER
|
||||
- POSTGRES_PASSWORD
|
||||
- POSTGRES_DB
|
||||
|
||||
beat:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
command: celery -A artel beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
- ./:/app
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- SECRET_KEY
|
||||
- DATABASE_URL
|
||||
depends_on:
|
||||
- comfy
|
||||
- rabbit
|
||||
|
||||
worker:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
command: celery -A artel worker -l info
|
||||
volumes:
|
||||
- ./:/app
|
||||
- ./media:/app/media
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- SECRET_KEY
|
||||
- DATABASE_URL
|
||||
depends_on:
|
||||
- comfy
|
||||
- rabbit
|
||||
- beat
|
||||
|
||||
adminer:
|
||||
image: adminer
|
||||
|
@ -49,3 +96,4 @@ services:
|
|||
volumes:
|
||||
media:
|
||||
db:
|
||||
rabbitmq_data:
|
|
@ -8,6 +8,10 @@ phonenumbers==8.13.13
|
|||
django-phonenumber-field==7.1.0
|
||||
factory-boy==3.2.1
|
||||
pdfkit==1.0.0
|
||||
celery==5.3.1
|
||||
django-celery-beat==2.5.0
|
||||
django-celery-results==2.5.1
|
||||
easy_thumbnails==2.8.5
|
||||
num2words==0.5.12
|
||||
sentry-sdk==1.28.0
|
||||
pandas==2.0.3
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.10 on 2023-09-09 16:42
|
||||
|
||||
from django.db import migrations
|
||||
import easy_thumbnails.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("store", "0013_producttemplateparam_alter_product_params_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="productimage",
|
||||
name="image",
|
||||
field=easy_thumbnails.fields.ThumbnailerImageField(upload_to=""),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="producttemplateimage",
|
||||
name="image",
|
||||
field=easy_thumbnails.fields.ThumbnailerImageField(upload_to=""),
|
||||
)
|
||||
]
|
|
@ -23,6 +23,7 @@ from django.template import (
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.db.models.signals import m2m_changed
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
from django.dispatch import receiver
|
||||
|
||||
from modelcluster.models import ClusterableModel
|
||||
from modelcluster.fields import ParentalKey
|
||||
|
@ -35,18 +36,21 @@ from wagtail import fields as wagtail_fields
|
|||
from taggit.managers import TaggableManager
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
from num2words import num2words
|
||||
from easy_thumbnails.fields import ThumbnailerImageField
|
||||
from easy_thumbnails.signals import saved_file
|
||||
|
||||
from mailings.models import (
|
||||
OutgoingEmail,
|
||||
Attachment
|
||||
)
|
||||
from artel.tasks import generate_thumbnails
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseImageModel(models.Model):
|
||||
image = models.ImageField()
|
||||
image = ThumbnailerImageField()
|
||||
is_main = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
|
@ -129,7 +133,7 @@ class ProductTemplateImage(BaseImageModel):
|
|||
template = ParentalKey(
|
||||
ProductTemplate, on_delete=models.CASCADE, related_name="template_images"
|
||||
)
|
||||
image = models.ImageField()
|
||||
image = ThumbnailerImageField()
|
||||
is_main = models.BooleanField(default=False)
|
||||
|
||||
|
||||
|
@ -532,3 +536,11 @@ class OrderDocument(models.Model):
|
|||
template = Template(content)
|
||||
content = template.render(context)
|
||||
return pdfkit.from_string(content, False)
|
||||
|
||||
|
||||
@receiver(saved_file)
|
||||
def generate_thumbnails_async(sender, fieldfile, **kwargs):
|
||||
generate_thumbnails.delay(
|
||||
model=sender, pk=fieldfile.instance.pk,
|
||||
field=fieldfile.field.name
|
||||
)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import logging
|
||||
import celery
|
||||
from django.conf import settings
|
||||
from easy_thumbnails.files import generate_all_aliases
|
||||
|
||||
from mailings.models import OutgoingEmail
|
||||
from store.models import Product
|
||||
|
@ -8,8 +10,8 @@ from store.admin import ProductAdmin
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# TODO - those should be modified to be celery tasks
|
||||
|
||||
@celery.shared_task(name="send_produt_request_email")
|
||||
def send_produt_request_email(variant_pk: int):
|
||||
try:
|
||||
variant = Product.objects.get(pk=variant_pk)
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
{% load static %}
|
||||
|
||||
{% load thumbnail %}
|
||||
<div class="card h-100" >
|
||||
<div class="card-header text-truncate">{{item.title}}</div>
|
||||
<div class="card-body p-0">
|
||||
<img src="{{item.main_image.image.url}}"
|
||||
class="img-fluid img-thumbnail rounded mx-auto d-block mt-2 mb-2" style="width: 13rem; height: 15rem;" alt="{{item.title}}">
|
||||
<div class="card-header text-truncate">{{item.title}}</div>
|
||||
<div class="card-body p-0">
|
||||
<img src="{{ item.main_image.image|thumbnail_url:'image_40_60' }}" class="d-block d-sm-none img-fluid rounded mx-auto" alt="{{item.title}}">
|
||||
|
||||
<div class="card-footer row d-flex m-0">
|
||||
<div class="col text-center">
|
||||
<img src="{{ item.main_image.image|thumbnail_url:'image_60_90' }}" class="d-none d-sm-block d-md-none img-fluid rounded mx-auto" alt="{{item.title}}">
|
||||
|
||||
<img src="{{ item.main_image.image|thumbnail_url:'image_80_120' }}" class="d-none d-md-block d-lg-none img-fluid rounded mx-auto" alt="{{item.title}}">
|
||||
|
||||
<img src="{{ item.main_image.image|thumbnail_url:'image_120_180' }}" class="d-none d-lg-block d-xl-none img-fluid rounded mx-auto" alt="{{item.title}}">
|
||||
|
||||
<img src="{{ item.main_image.image|thumbnail_url:'image_160_240' }}" class="d-none d-xl-block img-fluid rounded mx-auto" alt="{{item.title}}">
|
||||
</div>
|
||||
<div class="card-footer row d-flex m-0">
|
||||
<div class="col text-center">
|
||||
<a href="{% url 'product-configure' item.id %}" class="btn btn-primary">Konfiguruj</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -53,7 +53,7 @@ class CartView(TemplateView):
|
|||
|
||||
class CartActionView(ViewSet):
|
||||
|
||||
# TODO - test this, currently not in use
|
||||
# NOTE - currently not in use
|
||||
@action(detail=False, methods=["get"], url_path="list-products")
|
||||
def list_products(self, request):
|
||||
# get cart items
|
||||
|
@ -144,7 +144,7 @@ class ConfigureProductSummaryView(View):
|
|||
def post(self, request, variant_pk: int, *args, **kwargs):
|
||||
# Here just send the email with product request
|
||||
variant = Product.objects.get(pk=variant_pk)
|
||||
send_produt_request_email(variant.pk)
|
||||
send_produt_request_email.apply_async(args=[variant.pk])
|
||||
messages.success(request, "Zapytanie o produkt zostało wysłane")
|
||||
context = self.get_context_data(variant_pk)
|
||||
return HttpResponseRedirect(context["store_url"])
|
||||
|
|
Ładowanie…
Reference in New Issue