parent
9800358b25
commit
a181c54093
12 changed files with 324 additions and 0 deletions
@ -0,0 +1 @@ |
||||
default_app_config = 'contact_us.apps.ContactUsConfig' |
||||
@ -0,0 +1,7 @@ |
||||
from django.apps import AppConfig |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
|
||||
|
||||
class ContactUsConfig(AppConfig): |
||||
name = 'contact_us' |
||||
verbose_name = _("Contact requests") |
||||
@ -0,0 +1,5 @@ |
||||
from contact_us.forms import ContactUsForm |
||||
|
||||
|
||||
def contact_us_form(request): |
||||
return {'contact_us_form': ContactUsForm()} |
||||
@ -0,0 +1,85 @@ |
||||
from crispy_forms.helper import FormHelper |
||||
from crispy_forms.layout import Layout, Div, HTML, Field, Submit |
||||
from django import forms |
||||
from django.conf import settings |
||||
from django.urls import reverse_lazy |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
|
||||
from ckeditor.widgets import CKEditorWidget |
||||
|
||||
|
||||
from .mixins import RequestNotifiable |
||||
from .models import ( |
||||
Request, |
||||
STATUS_NEW, STATUS_REJECTED, |
||||
STATUS_PROCESSED, STATUS_IN_PROCESSING |
||||
) |
||||
|
||||
# -------------------------------- Client-side forms -----------------------------------# |
||||
|
||||
|
||||
class ContactUsForm(RequestNotifiable, forms.ModelForm): |
||||
|
||||
field_template = 'bootstrap/forms/product_search.html' |
||||
|
||||
def __init__(self, *args, **kwargs): |
||||
self.helper = FormHelper() |
||||
self.helper.form_action = reverse_lazy('contact_us:send') |
||||
self.helper.form_method = 'post' |
||||
self.helper.layout = Layout( |
||||
HTML(""" |
||||
<div class="left-menu__title"> |
||||
Не нашли нужную программу или разработчика? |
||||
Заполните форму и с Вами свяжется наш специалист. |
||||
</div>"""), |
||||
Field('name', css_class="left-menu__text", placeholder=_("Имя"), template=self.field_template), |
||||
Field('email', css_class="left-menu__text", placeholder=_("Email"), template=self.field_template), |
||||
Field('subject', css_class="left-menu__text", placeholder=_("Название продукта"), template=self.field_template), |
||||
Field('phone', css_class="left-menu__text", placeholder=_("Номер телефона"), template=self.field_template), |
||||
Submit('send', _("Отправить"), css_class="left-menu__btn") |
||||
) |
||||
super(ContactUsForm, self).__init__(*args, **kwargs) |
||||
self.init_fields(self.fields) |
||||
|
||||
def init_fields(self, fields): |
||||
for field_name in fields: |
||||
fields[field_name].required = True |
||||
|
||||
def save(self, commit=True): |
||||
self.instance.status = STATUS_NEW |
||||
return super().save(commit) |
||||
|
||||
def send_email(self, request, files=()): |
||||
context = { |
||||
'from_email': self.instance.type.author.email, |
||||
'bcc': self.get_def_email(settings) if self.get_def_email(settings) is not None else (), |
||||
'recipients': self.instance.type.author.email, |
||||
'context': { |
||||
'username': self.instance.name, |
||||
'email': self.instance.email, |
||||
'subject': self.instance.subject, |
||||
'message': self.instance.message, |
||||
'sent_at': self.instance.create_at, |
||||
'attachments': files, |
||||
'edit_link': request.scheme + "://" + request.get_host() + reverse_lazy( |
||||
'admin:{}_{}_change'.format( |
||||
self.instance._meta.app_label, |
||||
self.instance._meta.object_name.lower()), |
||||
args=(self.instance.id,) |
||||
).__str__(), |
||||
}, |
||||
'files': [], |
||||
'send_at_date': self.instance.create_at, |
||||
|
||||
} |
||||
self.send_request_notification( |
||||
context, |
||||
) |
||||
|
||||
@property |
||||
def is_request_sent(self): |
||||
return self.notification_sent |
||||
|
||||
class Meta: |
||||
model = Request |
||||
fields = ('name', 'email', 'subject', 'phone') |
||||
@ -0,0 +1,58 @@ |
||||
from django.template.loader import get_template |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
|
||||
|
||||
class RequestNotifiable(object): |
||||
MAIL_CATEGORY = 'Request' |
||||
|
||||
SLUG_NOTIFICATION = 'notification' |
||||
SLUG_RESPONSE = 'response' |
||||
|
||||
def __init__(self, *args, **kwargs): |
||||
super(RequestNotifiable, self).__init__(*args, **kwargs) |
||||
|
||||
def get_mail_template(self, **kwargs): |
||||
return None |
||||
# return MailTemplate.objects.filter(**kwargs).first() |
||||
|
||||
def send_request_notification(self, context): |
||||
""" |
||||
:param context |
||||
:param template_path string: |
||||
:return None: |
||||
""" |
||||
notification = self.get_mail_template( |
||||
slug=self.SLUG_NOTIFICATION, |
||||
) |
||||
|
||||
kwargs = { |
||||
'subject': _('New contact us request'), |
||||
'message': get_template('contact_us/contact_email_notification.html').template.source, |
||||
} |
||||
if not notification: |
||||
kwargs.update({ |
||||
'name': 'Admin notification', |
||||
'slug': self.SLUG_NOTIFICATION, |
||||
'num_of_retries': 3, |
||||
'is_html': True |
||||
}) |
||||
# MailTemplate.objects.create(**kwargs) |
||||
else: |
||||
notification.subject = kwargs.get('subject') |
||||
notification.message = kwargs.get('message') |
||||
notification.save() |
||||
|
||||
# send_db_mail( |
||||
# self.SLUG_NOTIFICATION, |
||||
# context.get('recipients'), |
||||
# context.get('subject'), |
||||
# context.get('context'), |
||||
# from_email=context.get('from_email', tuple()), |
||||
# bcc=context.get('bcc', tuple()), |
||||
# files=context.get('files', tuple()), |
||||
# send_at_date=context.get('send_at_date'), |
||||
# retry=True, |
||||
# retry_delay=300, |
||||
# max_retries=3, |
||||
# use_celery=celery_supported() |
||||
# ) |
||||
@ -0,0 +1,69 @@ |
||||
import os |
||||
from django.conf import settings |
||||
from django.contrib.auth import get_user_model |
||||
from django.core.validators import RegexValidator |
||||
from django.db import models |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
|
||||
# Create your models here. |
||||
from core.models import AbstractStatusModel, STATUS_DELETED |
||||
|
||||
# --------------------- REQUEST STATUS LIST -------------------- |
||||
|
||||
STATUS_NEW = 0 |
||||
from core.models import AbstractStatusModel, STATUS_NEW, STATUS_CHOICES, STATUS_ACTIVE, STATUS_DELETED |
||||
|
||||
# --------------------- REQUEST STATUS LIST -------------------- |
||||
|
||||
STATUS_IN_PROCESSING = 10 |
||||
STATUS_PROCESSED = 20 |
||||
STATUS_REJECTED = 40 |
||||
|
||||
REQUEST_STATUS_CHOICES = ( |
||||
STATUS_CHOICES[0], |
||||
(STATUS_IN_PROCESSING, _('Processing')), |
||||
(STATUS_PROCESSED, _('Processed')), |
||||
(STATUS_REJECTED, _('Rejected')), |
||||
STATUS_CHOICES[-1] |
||||
) |
||||
|
||||
REQUEST_DEFAULT_STATUS = STATUS_NEW |
||||
|
||||
# ----------------- REQUEST FILE STATUS LIST ------------------ |
||||
|
||||
FILE_REQUEST_STATUS_CHOICES = ( |
||||
(STATUS_ACTIVE, _('Active')), |
||||
(STATUS_DELETED, _('Deleted')), |
||||
) |
||||
|
||||
FILE_REQUEST_DEFAULT_STATUS = STATUS_ACTIVE |
||||
|
||||
|
||||
class Request(AbstractStatusModel): |
||||
name = models.CharField(_('Name'), max_length=255) |
||||
email = models.EmailField(_('Email')) |
||||
subject = models.CharField(_('Subject'), max_length=500) |
||||
message = models.TextField(blank=True, null=True) |
||||
phone_regex = RegexValidator(regex=r'^\((+7)|8)?\d{10}$', |
||||
message="Phone number must be entered in the format: '+99999999999'. Up to 12 digits allowed.") |
||||
phone = models.CharField(validators=[phone_regex], max_length=12, blank=True, null=True) |
||||
status = models.SmallIntegerField(_('Status'), default=REQUEST_DEFAULT_STATUS, choices=REQUEST_STATUS_CHOICES) |
||||
|
||||
@property |
||||
def is_status_processed(self): |
||||
return self.status == STATUS_PROCESSED |
||||
|
||||
@property |
||||
def is_status_rejected(self): |
||||
return self.status == STATUS_REJECTED |
||||
|
||||
@property |
||||
def is_status_processing(self): |
||||
return self.status == STATUS_IN_PROCESSING |
||||
|
||||
def __str__(self): |
||||
return self.subject |
||||
|
||||
class Meta: |
||||
verbose_name = _('Request') |
||||
verbose_name_plural = _('Requests') |
||||
@ -0,0 +1,8 @@ |
||||
from django.contrib.admin.templatetags.admin_modify import submit_row, register |
||||
|
||||
|
||||
@register.inclusion_tag('admin/contact_us/custom_submit_line.html', takes_context=True) |
||||
def custom_submit_row(context): |
||||
ctx = submit_row(context) |
||||
ctx['show_answer'] = context.get('show_answer',True) |
||||
return ctx |
||||
@ -0,0 +1,22 @@ |
||||
from django.test import TestCase |
||||
|
||||
from core.tests import BehaviourTestCaseMixin |
||||
|
||||
from .models import Request |
||||
|
||||
|
||||
# Create your tests here. |
||||
class SendRequestWithTestCase(BehaviourTestCaseMixin, TestCase): |
||||
model = Request |
||||
|
||||
def create_instance(self, **kwargs): |
||||
return self.get_model() |
||||
|
||||
def send_form_without_attachments_by_db_mailer(self): |
||||
pass |
||||
|
||||
def send_form_with_attachments_by_db_mailer(self): |
||||
pass |
||||
|
||||
def save_attachments_locally(self): |
||||
pass |
||||
@ -0,0 +1,7 @@ |
||||
from django.conf.urls import url |
||||
|
||||
from .views import ContactUsFormView |
||||
|
||||
urlpatterns = [ |
||||
url(r'^send/$', ContactUsFormView.as_view(), name='send'), |
||||
] |
||||
@ -0,0 +1,62 @@ |
||||
import logging |
||||
|
||||
from django.contrib import messages |
||||
from django.contrib.messages.views import SuccessMessageMixin |
||||
from django.db import transaction |
||||
from django.urls import reverse_lazy |
||||
from django.views.generic import FormView |
||||
from django.utils.translation import ugettext_lazy as _ |
||||
|
||||
from .forms import ContactUsForm |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
|
||||
|
||||
# Create your views here. |
||||
class ContactUsFormView(SuccessMessageMixin, FormView): |
||||
template_name = None |
||||
form_class = ContactUsForm |
||||
http_method_names = ['post'] |
||||
success_message = _('Request has been sent successfully!') |
||||
error_message = _('Some errors occurred during sending the request. Check the input fields or try latter.') |
||||
|
||||
def get_initial(self): |
||||
initial = super().get_initial() |
||||
if self.request.method == "GET": |
||||
initial['type'] = RequestType.objects.order_by('order').first() |
||||
if self.request.user.is_authenticated(): |
||||
initial['name'] = self.request.user.profile.get_full_name(self.request, self.request.user.profile) |
||||
initial['email'] = self.request.user.email |
||||
return initial |
||||
|
||||
def form_valid(self, form): |
||||
try: |
||||
with transaction.atomic(): |
||||
if self.request.user.is_authenticated(): |
||||
form.instance.user = self.request.user |
||||
form.save() |
||||
files = [] |
||||
if len(self.request.FILES) > 0: |
||||
attachments = AttachmentFormSet(self.request.POST, self.request.FILES, form_kwargs={'request': form.instance}) |
||||
if attachments.is_valid(): |
||||
attachments.save() |
||||
files = attachments.get_file_absolute_urls(self.request) |
||||
form.send_email(self.request, files) |
||||
return super().form_valid(form) |
||||
except ValueError as ve: |
||||
logger.critical(ve) |
||||
messages.error(self.request, self.error_message, 'danger') |
||||
except Exception as e: |
||||
logger.critical(e) |
||||
messages.error(self.request, self.error_message, 'danger') |
||||
|
||||
return self.form_invalid(form) |
||||
|
||||
def form_invalid(self, form): |
||||
context = self.get_context_data() |
||||
if len(form.errors) > 0: |
||||
context['form_show_errors'] = True |
||||
return self.render_to_response(context) |
||||
|
||||
def get_success_url(self): |
||||
return super().get_success_url() |
||||
Loading…
Reference in new issue