Merge branch 'main' of ssh://forge.citizen4.eu:2222/mtyton/comfy
commit
e67806992b
|
@ -3,7 +3,7 @@ steps:
|
|||
image: docker:24.0.6
|
||||
secrets: []
|
||||
commands:
|
||||
- docker compose -f artel/docker-compose-test.yml build
|
||||
- docker compose -f artel/docker-compose-test.yml build --no-cache
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
when:
|
||||
|
|
|
@ -42,6 +42,7 @@ INSTALLED_APPS = [
|
|||
"mailings",
|
||||
"blog",
|
||||
"search",
|
||||
"setup",
|
||||
"wagtail.contrib.forms",
|
||||
"wagtail.contrib.redirects",
|
||||
"wagtail.embeds",
|
||||
|
@ -70,7 +71,10 @@ INSTALLED_APPS = [
|
|||
"easy_thumbnails",
|
||||
]
|
||||
|
||||
|
||||
MIDDLEWARE = [
|
||||
"setup.middleware.CheckSetupMiddleware",
|
||||
"setup.middleware.CheckShopMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
|
@ -92,6 +96,7 @@ TEMPLATES = [
|
|||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
'setup.context_processors.config_context_processor',
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
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,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-question-circle" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z"/>
|
||||
</svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 719 B |
|
@ -37,9 +37,17 @@
|
|||
{% wagtailuserbar %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mt-5 ml-2">
|
||||
{% if navbar_position == 'top' %}
|
||||
<div class="col-md-12 mt-5 ml-2">
|
||||
{% main_menu max_levels=3 template="menu/custom_main_menu.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if navbar_position == 'left' %}
|
||||
<div class="col-md-3 mt-5 ml-2">
|
||||
{% main_menu max_levels=3 template="menu/custom_main_menu.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-md-9 mt-5 ml-2">
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{message.tags}}" role="alert">
|
||||
|
@ -48,6 +56,11 @@
|
|||
{% endfor %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% if navbar_position == 'right' %}
|
||||
<div class="col-md-3 mt-5 ml-2">
|
||||
{% main_menu max_levels=3 template="menu/custom_main_menu.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
|
||||
<div class="d-flex flex-column flex-shrink-0 p-3 mr-5">
|
||||
<img src="{% static 'images/icons/las_ruinas_PL.png' %}" class="img-fluid rounded mx-auto d-block mt-3" style="width: 10rem; height: 10 rem;" alt="Portal Logo"/>
|
||||
<img src="{{logo}}" class="img-fluid rounded mx-auto d-block mt-3" style="width: 10rem; height: 10 rem;" alt="Portal Logo"/>
|
||||
<hr>
|
||||
<ul class="nav navbar-nav">
|
||||
{% for item in menu_items %}
|
||||
|
@ -22,5 +22,7 @@
|
|||
</div>
|
||||
<div class="d-flex flex-column flex-shrink-0 p-3 mr-5">
|
||||
<hr>
|
||||
<a href={% url 'cart' %} alt="Koszyk" > Koszyk </a>
|
||||
{% if shop_enabled %}
|
||||
<a href={% url 'cart' %} alt="Koszyk" > Koszyk </a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from setup.models import ComfyConfig
|
||||
|
||||
|
||||
class BaseComfyTestCaseMixin:
|
||||
def setUp(self):
|
||||
ComfyConfig.objects.create(
|
||||
logo="images/logo.png",
|
||||
navbar_position="left",
|
||||
shop_enabled=True,
|
||||
active=True,
|
||||
)
|
||||
super().setUp()
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf import settings
|
||||
from django.urls import (
|
||||
include,
|
||||
include,
|
||||
path
|
||||
)
|
||||
from django.contrib import admin
|
||||
|
@ -12,15 +12,18 @@ from wagtail.documents import urls as wagtaildocs_urls
|
|||
|
||||
from search import views as search_views
|
||||
|
||||
handler404 = 'artel.views.my_custom_page_not_found_view'
|
||||
from setup import views as setup_views
|
||||
|
||||
|
||||
handler404 = 'artel.views.my_custom_page_not_found_view'
|
||||
|
||||
urlpatterns = [
|
||||
path("django-admin/", admin.site.urls),
|
||||
path("admin/", include(wagtailadmin_urls)),
|
||||
path("documents/", include(wagtaildocs_urls)),
|
||||
path("search/", search_views.search, name="search"),
|
||||
path("store-app/", include("store.urls"))
|
||||
path('store-app/', include('store.urls')),
|
||||
path('setup/', include('setup.urls')),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ services:
|
|||
test_beat:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
dockerfile: Dockerfile.local
|
||||
command: celery -A artel beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
|
||||
environment:
|
||||
- SECRET_KEY=RandomKey
|
||||
|
@ -48,7 +48,7 @@ services:
|
|||
test_worker:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
dockerfile: Dockerfile.local
|
||||
command: celery -A artel worker -l info
|
||||
environment:
|
||||
- SECRET_KEY=RandomKey
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
from wagtail.contrib.modeladmin.options import (
|
||||
ModelAdmin,
|
||||
ModelAdminGroup,
|
||||
modeladmin_register
|
||||
)
|
||||
|
||||
from setup.models import ComfyConfig
|
||||
|
||||
class ConfigAdmin(ModelAdmin):
|
||||
model = ComfyConfig
|
||||
list_display = ("updated", )
|
||||
|
||||
|
||||
class SetupModelAdminGroup(ModelAdminGroup):
|
||||
menu_label = "Setup"
|
||||
menu_icon = 'folder-open-inverse'
|
||||
menu_order = 200
|
||||
items = (
|
||||
ConfigAdmin,
|
||||
)
|
||||
|
||||
modeladmin_register(SetupModelAdminGroup)
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SetupConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "setup"
|
|
@ -0,0 +1,10 @@
|
|||
from django.conf import settings
|
||||
|
||||
from setup.models import ComfyConfig
|
||||
from setup.serializers import ConfigSerializers
|
||||
|
||||
|
||||
def config_context_processor(request):
|
||||
config = ComfyConfig.objects.filter(active=True).first()
|
||||
serializer = ConfigSerializers(instance=config)
|
||||
return serializer.data
|
|
@ -0,0 +1,62 @@
|
|||
import logging
|
||||
|
||||
from typing import Any, Mapping, Optional, Type, Union
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.validators import FileExtensionValidator
|
||||
from django.forms.utils import ErrorList
|
||||
|
||||
|
||||
from setup.models import (
|
||||
ComfyConfig,
|
||||
NavbarPosition
|
||||
)
|
||||
from store import SHOP_ESSENTIAL_MAIL_TEMPLATES
|
||||
from mailings.models import MailTemplate
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SiteConfigurationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ComfyConfig
|
||||
fields = [
|
||||
"logo", "navbar_position", "shop_enabled"
|
||||
]
|
||||
widgets = {
|
||||
"logo": forms.FileInput(attrs={"class": "form-control"}),
|
||||
"navbar_position": forms.Select(attrs={"class": "form-control"}),
|
||||
"shop_enabled": forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
||||
}
|
||||
|
||||
navbar_position = forms.ChoiceField(
|
||||
choices=NavbarPosition.choices,
|
||||
widget=forms.Select(attrs={"class": "form-control"}),
|
||||
initial=NavbarPosition.LEFT.value
|
||||
)
|
||||
|
||||
|
||||
class MailTemplatesFileUploadForm(forms.Form):
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
for field_name, desc in SHOP_ESSENTIAL_MAIL_TEMPLATES.items():
|
||||
label = field_name.replace("_", " ").capitalize()
|
||||
self.fields[field_name] = forms.FileField(
|
||||
validators=[FileExtensionValidator(allowed_extensions=["html"])],
|
||||
help_text=desc, label=label, widget=forms.FileInput(attrs={"class": "form-control"})
|
||||
)
|
||||
|
||||
def save(self):
|
||||
counter = 0
|
||||
for filename, file in self.files.items():
|
||||
obj, _created = MailTemplate.objects.get_or_create(
|
||||
template_name=filename
|
||||
)
|
||||
obj.template = file
|
||||
obj.save()
|
||||
if _created:
|
||||
counter +=1
|
||||
logger.info(f"Created {counter} mail templates")
|
||||
return MailTemplate.objects.count() >= len(SHOP_ESSENTIAL_MAIL_TEMPLATES.keys())
|
|
@ -0,0 +1,57 @@
|
|||
import logging
|
||||
from django.shortcuts import redirect
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
|
||||
from store.models import ProductListPage
|
||||
from setup.models import ComfyConfig
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CheckSetupMiddleware(object):
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
config = None
|
||||
try:
|
||||
config = ComfyConfig.objects.get(active=True)
|
||||
except ComfyConfig.DoesNotExist:
|
||||
if (not request.path_info.startswith('/setup') and not request.path_info.startswith('/admin')
|
||||
and not request.path_info.startswith('/media') and not request.path_info.startswith('/static')):
|
||||
return redirect('/setup/')
|
||||
except ComfyConfig.MultipleObjectsReturned:
|
||||
config = ComfyConfig.objects.first()
|
||||
logger.exception("Multiple ComfyConfig objects found. Using first one.")
|
||||
|
||||
if config and request.path_info.startswith('/setup'):
|
||||
return redirect('/')
|
||||
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
|
||||
class CheckShopMiddleware(object):
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def _check_if_store_request(self, request):
|
||||
if request.path_info.startswith('/store-app/'):
|
||||
return True
|
||||
if request.path_info == "/":
|
||||
return False
|
||||
return ProductListPage.objects.filter(url_path__endswith=request.path_info).exists()
|
||||
|
||||
def __call__(self, request):
|
||||
config = ComfyConfig.objects.filter(active=True).first()
|
||||
if config and not config.shop_enabled and self._check_if_store_request(request):
|
||||
if settings.DEBUG:
|
||||
return HttpResponse(
|
||||
status=500, content="Store is not enabled please turn it on in admin panel"
|
||||
)
|
||||
else:
|
||||
return redirect('/')
|
||||
|
||||
response = self.get_response(request)
|
||||
return response
|
|
@ -0,0 +1,28 @@
|
|||
# Generated by Django 4.1.10 on 2023-08-17 20:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ComfyConfig",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("logo", models.ImageField(upload_to="images")),
|
||||
(
|
||||
"navbar_position",
|
||||
models.CharField(
|
||||
choices=[("top", "Top"), ("left", "Left"), ("right", "Right")], default="top", max_length=20
|
||||
),
|
||||
),
|
||||
("shop_enabled", models.BooleanField(default=False)),
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("updated", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 4.1.10 on 2023-09-17 09:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("setup", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="comfyconfig",
|
||||
name="active",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class NavbarPosition(models.TextChoices):
|
||||
TOP = 'top'
|
||||
LEFT = 'left'
|
||||
RIGHT = 'right'
|
||||
|
||||
|
||||
class ComfyConfig(models.Model):
|
||||
logo = models.ImageField(upload_to='images')
|
||||
navbar_position = models.CharField(
|
||||
max_length=20,
|
||||
choices=NavbarPosition.choices, default=NavbarPosition.TOP
|
||||
)
|
||||
shop_enabled = models.BooleanField(default=False)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
active = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return f'Comfy Config - updated: {self.updated}'
|
|
@ -0,0 +1,11 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from setup.models import ComfyConfig
|
||||
|
||||
|
||||
class ConfigSerializers(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ComfyConfig
|
||||
fields = [
|
||||
'logo', 'navbar_position', 'shop_enabled'
|
||||
]
|
|
@ -0,0 +1,53 @@
|
|||
{% extends 'setup/setup_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
{% block form %}
|
||||
<form enctype="multipart/form-data" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="card-body">
|
||||
<h1 class="text-center">Your Config</h1>
|
||||
<div class="row mb-3 mt-5">
|
||||
<div class="col-2">
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>
|
||||
Logo:
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<img src="{{config.logo.url}}" alt="Logo" class="img-fluid">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>
|
||||
<label for="id_navbar_position" class="form-label">Navbar Position:</label>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
{{config.navbar_position}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>
|
||||
<label for="id_shop_enabled" class="form-label">Shop Enabled:</label>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
{% if config.shop_enabled %}yes{% else %}no{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer text-muted text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Submit">
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,58 @@
|
|||
{% extends 'setup/setup_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
{% block form %}
|
||||
<form enctype="multipart/form-data" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="card-body">
|
||||
<h1 class="text-center">Configure Your Comfy Basics</h1>
|
||||
<div class="row mb-3 mt-5">
|
||||
<div class="col-2">
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>
|
||||
<label for="id_logo" class="form-label">{{form.logo.label}}</label>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
{{form.logo}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>
|
||||
<label for="id_navbar_position" class="form-label">{{form.navbar_position.label}}</label>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
{{form.navbar_position}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<h3>
|
||||
<label for="id_shop_enabled" class="form-label">{{form.shop_enabled.label}}</label>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
{{form.shop_enabled}}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.errors %}
|
||||
<div class="alert alert-danger">
|
||||
{{ form.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-muted text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Next">
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,36 @@
|
|||
{% extends 'setup/setup_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
{% block form %}
|
||||
<form enctype="multipart/form-data" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="card-body ">
|
||||
<h1 class="text-center">Configure Your Comfy Essential Mailings</h1>
|
||||
{% for field in form %}
|
||||
<div class="row mb-3 mt-5">
|
||||
<div class="col-1">
|
||||
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h3>
|
||||
<label for="id_logo" class="form-label">{{field.label}}</label>
|
||||
<img src = "{% static 'images/icons/question-circle.svg' %}" alt="?"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="{{field.help_text}}"/>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
{{field}}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if form.errors %}
|
||||
<div class="alert alert-danger">
|
||||
{{ form.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-muted text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,14 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div>
|
||||
<div class="card">
|
||||
<div class="card-header text-center">
|
||||
<!--<img src="" width="15%">-->
|
||||
</div>
|
||||
{% block form %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,86 @@
|
|||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
|
||||
from setup import models as setup_models
|
||||
from store import SHOP_ESSENTIAL_MAIL_TEMPLATES
|
||||
from mailings.models import MailTemplate
|
||||
|
||||
|
||||
TEST_IMAGE = (
|
||||
b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x00\x00\x00\x21\xf9\x04'
|
||||
b'\x01\x0a\x00\x01\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02'
|
||||
b'\x02\x4c\x01\x00\x3b'
|
||||
)
|
||||
|
||||
|
||||
class SetupTestCase(TestCase):
|
||||
def test_get_setup_first_step_get_success(self):
|
||||
response = self.client.get(reverse('setup-page'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'setup/config.html')
|
||||
|
||||
def test_post_setup_first_step_post_success_shop_enabled(self):
|
||||
response = self.client.post(reverse('setup-page'), data={
|
||||
"logo": SimpleUploadedFile('filename.png', content=TEST_IMAGE, content_type='image/jpeg'),
|
||||
"navbar_position": setup_models.NavbarPosition.LEFT.value,
|
||||
"shop_enabled": True
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('setup-mailings'))
|
||||
self.assertEqual(setup_models.ComfyConfig.objects.count(), 1)
|
||||
config = setup_models.ComfyConfig.objects.first()
|
||||
self.assertEqual(config.navbar_position, setup_models.NavbarPosition.LEFT.value)
|
||||
self.assertEqual(config.shop_enabled, True)
|
||||
self.assertEqual(config.logo.read(), TEST_IMAGE)
|
||||
self.assertFalse(config.active)
|
||||
|
||||
def test_post_setup_first_step_post_success_shop_disabled(self):
|
||||
response = self.client.post(reverse('setup-page'), data={
|
||||
"logo": SimpleUploadedFile('filename.png', content=TEST_IMAGE, content_type='image/jpeg'),
|
||||
"navbar_position": setup_models.NavbarPosition.LEFT.value,
|
||||
"shop_enabled": False
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('setup-complete'))
|
||||
self.assertEqual(setup_models.ComfyConfig.objects.count(), 1)
|
||||
config = setup_models.ComfyConfig.objects.first()
|
||||
self.assertEqual(config.navbar_position, setup_models.NavbarPosition.LEFT.value)
|
||||
self.assertEqual(config.shop_enabled, False)
|
||||
self.assertEqual(config.logo.read(), TEST_IMAGE)
|
||||
self.assertFalse(config.active)
|
||||
|
||||
def test_post_setup_first_step_post_failure(self):
|
||||
response = self.client.post(reverse('setup-page'), data={
|
||||
"logo": "",
|
||||
"navbar_position": setup_models.NavbarPosition.LEFT.value,
|
||||
"shop_enabled": True
|
||||
})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(setup_models.ComfyConfig.objects.count(), 0)
|
||||
self.assertTemplateUsed(response, 'setup/config.html')
|
||||
self.assertFormError(response, 'form', 'logo', 'This field is required.')
|
||||
|
||||
def test_get_email_config_success(self):
|
||||
response = self.client.get(reverse('setup-mailings'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'setup/mailing.html')
|
||||
|
||||
def test_post_email_config_success(self):
|
||||
response = self.client.post(reverse('setup-mailings'), data={
|
||||
key: SimpleUploadedFile(
|
||||
f'{key}.html', content=b'<html></html>', content_type='text/html'
|
||||
) for key, _ in SHOP_ESSENTIAL_MAIL_TEMPLATES.items()
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('setup-complete'))
|
||||
self.assertEqual(MailTemplate.objects.count(), 3)
|
||||
self.assertEqual(MailTemplate.objects.filter(template_name__in=SHOP_ESSENTIAL_MAIL_TEMPLATES.keys()).count(), 3)
|
||||
|
||||
def test_post_email_config_failure(self):
|
||||
response = self.client.post(reverse('setup-mailings'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(MailTemplate.objects.count(), 0)
|
||||
self.assertTemplateUsed(response, 'setup/mailing.html')
|
||||
self.assertFormError(response, 'form', None, None, 'This field is required.')
|
|
@ -0,0 +1,11 @@
|
|||
from django.urls import (
|
||||
path
|
||||
)
|
||||
|
||||
from setup import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.SetupPageView.as_view(), name='setup-page'),
|
||||
path('mailings/', views.SetupMailingView.as_view(), name='setup-mailings'),
|
||||
path('complete/', views.SetupCompleteView.as_view(), name='setup-complete'),
|
||||
]
|
|
@ -0,0 +1,103 @@
|
|||
import logging
|
||||
import typing
|
||||
|
||||
from django.shortcuts import (
|
||||
render,
|
||||
redirect
|
||||
)
|
||||
from django.views import View
|
||||
from django.http import HttpRequest
|
||||
|
||||
from setup.forms import (
|
||||
SiteConfigurationForm,
|
||||
MailTemplatesFileUploadForm
|
||||
)
|
||||
from setup.models import ComfyConfig
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseSetupView(View):
|
||||
tempalte_name = None
|
||||
form_class = None
|
||||
next_step_view = None
|
||||
step = None
|
||||
|
||||
def get_context_data(self):
|
||||
return {
|
||||
"form": self.form_class()
|
||||
}
|
||||
|
||||
def get(self, request):
|
||||
return render(request, self.template_name, self.get_context_data())
|
||||
|
||||
def handle_posted_form(self, request: HttpRequest):
|
||||
form = self.form_class(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
return form.save(), {}
|
||||
context = self.get_context_data()
|
||||
context['form'] = form
|
||||
return None, context
|
||||
|
||||
def get_redirect(self, form_result: typing.Any=None):
|
||||
return redirect(self.next_step_view)
|
||||
|
||||
def post(self, request: HttpRequest):
|
||||
form_result, ctx = self.handle_posted_form(request)
|
||||
if form_result:
|
||||
return self.get_redirect(form_result)
|
||||
|
||||
return render(request, self.template_name, ctx)
|
||||
|
||||
|
||||
class SetupPageView(BaseSetupView):
|
||||
template_name = 'setup/config.html'
|
||||
next_step_view = 'setup-mailings'
|
||||
form_class = SiteConfigurationForm
|
||||
step = 1
|
||||
|
||||
def get_redirect(self, form_result: typing.Any=None):
|
||||
if form_result.shop_enabled:
|
||||
return super().get_redirect(form_result)
|
||||
return redirect('setup-complete')
|
||||
|
||||
def handle_posted_form(self, request: HttpRequest):
|
||||
result, ctx = super().handle_posted_form(request)
|
||||
if not result:
|
||||
return result, ctx
|
||||
|
||||
request.session['config_id'] = result.id
|
||||
return result, ctx
|
||||
|
||||
|
||||
class SetupMailingView(BaseSetupView):
|
||||
template_name = 'setup/mailing.html'
|
||||
next_step_view = 'setup-complete'
|
||||
form_class = MailTemplatesFileUploadForm
|
||||
step = 2
|
||||
|
||||
|
||||
class SetupCompleteView(BaseSetupView):
|
||||
template_name = 'setup/complete.html'
|
||||
step = 3
|
||||
|
||||
def _get_config(self, request: HttpRequest):
|
||||
config_id = request.session.get('config_id', None)
|
||||
if config_id is None:
|
||||
return redirect('setup-page')
|
||||
|
||||
return ComfyConfig.objects.get(id=config_id)
|
||||
|
||||
def get_context_data(self):
|
||||
return {
|
||||
"config": self._get_config(self.request)
|
||||
}
|
||||
|
||||
def post(self, request: HttpRequest):
|
||||
config = self._get_config(request)
|
||||
config.active = True
|
||||
config.save()
|
||||
|
||||
request.session.flush()
|
||||
return redirect('/')
|
|
@ -0,0 +1,8 @@
|
|||
SHOP_ESSENTIAL_MAIL_TEMPLATES = {
|
||||
"order_created_author": "Mail template to be send to "+
|
||||
"product manufacturer after order has been created",
|
||||
"order_created_customer": "Mail template to be send to "+
|
||||
"customer after order has been created",
|
||||
"product_request": "Mail template to be send to "+
|
||||
"product manufacturer after product request has been created",
|
||||
}
|
|
@ -415,6 +415,7 @@ class OrderManager(models.Manager):
|
|||
|
||||
payment_method = payment_method or PaymentMethod.objects.first()
|
||||
doc_templates = DocumentTemplate.objects.filter(
|
||||
# TODO - this should be optional...
|
||||
doc_type__in=[DocumentTypeChoices.AGREEMENT, DocumentTypeChoices.RECEIPT]
|
||||
)
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@ from django.urls import reverse
|
|||
from django.conf import settings
|
||||
|
||||
from store.tests import factories
|
||||
from artel.tests import BaseComfyTestCaseMixin
|
||||
|
||||
|
||||
|
||||
class SessionCartTestCase(APITestCase):
|
||||
class SessionCartTestCase(BaseComfyTestCaseMixin, APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
|
|
@ -4,9 +4,10 @@ from unittest.mock import patch
|
|||
|
||||
from store.tests import factories
|
||||
from store.loader import ProductLoader
|
||||
from artel.tests import BaseComfyTestCaseMixin
|
||||
|
||||
|
||||
class TestProductLoader(TestCase):
|
||||
class TestProductLoader(BaseComfyTestCaseMixin, TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.category = factories.ProductCategoryFactory()
|
||||
self.template = factories.ProductTemplateFactory(category=self.category)
|
||||
|
|
|
@ -9,9 +9,10 @@ from django.db import transaction
|
|||
from store.tests import factories
|
||||
from store import models as store_models
|
||||
from mailings.tests.factories import MailTemplateFactory
|
||||
from artel.tests import BaseComfyTestCaseMixin
|
||||
|
||||
|
||||
class ProductCategoryParamTestCase(TestCase):
|
||||
class ProductCategoryParamTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.category = factories.ProductCategoryFactory()
|
||||
|
@ -41,7 +42,7 @@ class ProductCategoryParamTestCase(TestCase):
|
|||
self.assertEqual(len(available_values), 3)
|
||||
|
||||
|
||||
class ProductTemplateParamValueTestCase(TestCase):
|
||||
class ProductTemplateParamValueTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.category = factories.ProductCategoryFactory()
|
||||
|
@ -69,7 +70,7 @@ class ProductTemplateParamValueTestCase(TestCase):
|
|||
self.assertEqual(proper_value, None)
|
||||
|
||||
|
||||
class ProductTestCase(TestCase):
|
||||
class ProductTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
|
||||
def test_template_params_one_value_success(self):
|
||||
product = factories.ProductFactory()
|
||||
|
@ -143,7 +144,7 @@ class ProductTestCase(TestCase):
|
|||
self.assertEqual(prod.price, 0)
|
||||
|
||||
|
||||
class OrderProductTestCase(TestCase):
|
||||
class OrderProductTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.author = factories.ProductAuthorFactory()
|
||||
|
@ -185,7 +186,7 @@ class OrderProductTestCase(TestCase):
|
|||
self.assertEqual(products.count(), 0)
|
||||
|
||||
|
||||
class OrderTestCase(TestCase):
|
||||
class OrderTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
self.author = factories.ProductAuthorFactory()
|
||||
|
|
|
@ -12,9 +12,10 @@ from store.tests.factories import (
|
|||
ProductFactory,
|
||||
ProductTemplateParamValueFactory
|
||||
)
|
||||
from artel.tests import BaseComfyTestCaseMixin
|
||||
|
||||
|
||||
class ConfigureProductViewTestCase(TestCase):
|
||||
class ConfigureProductViewTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
@ -94,5 +95,5 @@ class ConfigureProductViewTestCase(TestCase):
|
|||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
|
||||
class ConfigureProductSummaryViewTestCase(TestCase):
|
||||
class ConfigureProductSummaryViewTestCase(BaseComfyTestCaseMixin, TestCase):
|
||||
...
|
||||
|
|
Ładowanie…
Reference in New Issue