pax_global_header 0000666 0000000 0000000 00000000064 14245325761 0014523 g ustar 00root root 0000000 0000000 52 comment=2c50ed6c99b645fe0b80f221a3e62e40e90fed13
django-contact-form-2.0.1/ 0000775 0000000 0000000 00000000000 14245325761 0015357 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/.github/ 0000775 0000000 0000000 00000000000 14245325761 0016717 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/.github/workflows/ 0000775 0000000 0000000 00000000000 14245325761 0020754 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/.github/workflows/ci.yml 0000664 0000000 0000000 00000001346 14245325761 0022076 0 ustar 00root root 0000000 0000000 name: CI
on: [push]
env:
PYTHON_AKISMET_API_KEY: ${{ secrets.PYTHON_AKISMET_API_KEY }}
PYTHON_AKISMET_BLOG_URL: ${{ secrets.PYTHON_AKISMET_BLOG_URL }}
jobs:
tests:
name: tox on ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: "Install dependencies"
run: |
python -VV
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade virtualenv tox tox-gh-actions
- run: "python -m tox"
django-contact-form-2.0.1/.gitignore 0000664 0000000 0000000 00000000150 14245325761 0017343 0 ustar 00root root 0000000 0000000 *.pyc
__pycache__
*.egg-info
docs/_build/
dist/
.coverage
.python-version
.tox/
*.sh
build/
.mypy_cache
django-contact-form-2.0.1/LICENSE 0000664 0000000 0000000 00000002763 14245325761 0016374 0 ustar 00root root 0000000 0000000 Copyright (c) 2007-2022, James Bennett
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the author nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
django-contact-form-2.0.1/MANIFEST.in 0000664 0000000 0000000 00000000207 14245325761 0017114 0 ustar 00root root 0000000 0000000 include LICENSE
include MANIFEST.in
include AUTHORS
recursive-include docs *
include tox.ini
include runtests.py
graft src
graft tests
django-contact-form-2.0.1/README.rst 0000664 0000000 0000000 00000000736 14245325761 0017054 0 ustar 00root root 0000000 0000000 .. -*-restructuredtext-*-
.. image:: https://github.com/ubernostrum/django-contact-form/workflows/CI/badge.svg
:alt: CI status image
:target: https://github.com/ubernostrum/django-contact-form/actions?query=workflow%3ACI
This application provides extensible contact-form functionality for
`Django `_ sites.
Full documentation for all functionality is included and is also
`available online `_. django-contact-form-2.0.1/docs/ 0000775 0000000 0000000 00000000000 14245325761 0016307 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/docs/Makefile 0000664 0000000 0000000 00000012760 14245325761 0017755 0 ustar 00root root 0000000 0000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-contact-form.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-contact-form.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/django-contact-form"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-contact-form"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
django-contact-form-2.0.1/docs/conf.py 0000664 0000000 0000000 00000002416 14245325761 0017611 0 ustar 00root root 0000000 0000000 import os
import sys
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
extensions = ["sphinx.ext.intersphinx"]
templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "django-contact-form"
copyright = "2007-2022, James Bennett"
version = "2.0"
release = "2.0.1"
exclude_trees = ["_build"]
pygments_style = "sphinx"
htmlhelp_basename = "django-contact-formdoc"
latex_documents = [
(
"index",
"django-contact-form.tex",
"django-contact-form Documentation",
"James Bennett",
"manual",
),
]
intersphinx_mapping = {
"django": (
"https://docs.djangoproject.com/en/stable/",
"https://docs.djangoproject.com/en/stable/_objects/",
),
"python": ("https://docs.python.org/3", None),
}
if not on_rtd:
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Spelling check needs an additional module that is not installed by default.
# Add it only if spelling check is requested so docs can be generated without it.
if "spelling" in sys.argv:
extensions.append("sphinxcontrib.spelling")
# Spelling language.
spelling_lang = "en_US"
# Location of word list.
spelling_word_list_filename = "spelling_wordlist.txt"
django-contact-form-2.0.1/docs/faq.rst 0000664 0000000 0000000 00000011726 14245325761 0017617 0 ustar 00root root 0000000 0000000 .. _faq:
Frequently asked questions
==========================
The following notes answer some common questions, and may be useful to
you when installing, configuring or using django-contact-form.
What versions of Django and Python are supported?
-------------------------------------------------
As of django-contact-form |release|, Django 3.2 and 4.0 are
supported, on Python 3.7 (Django 3.2 only), 3.8, 3.9, and 3.10. Note
that Django 3.2's support for Python 3.10 was added in Django 3.2.9,
so you may experience issues with Python 3.10 and earlier Django 3.2
versions.
What license is django-contact-form under?
----------------------------------------------
django-contact-form is offered under a three-clause BSD-style
license; this is `an OSI-approved open-source license
`_, and allows you
a large degree of freedom in modifying and redistributing the
code. For the full terms, see the file `LICENSE` which came with
your copy of django-contact-form; if you did not receive a copy of
this file, you can view it online at
.
Why aren't there any default templates I can use?
-------------------------------------------------
Usable default templates, for an application designed to be widely
reused, are essentially impossible to produce; variations in site
design, block structure, etc. cannot be reliably accounted for. As
such, django-contact-form provides bare-bones (i.e., containing no
HTML structure whatsoever) templates in its source distribution to
enable running tests, and otherwise just provides good documentation
of all required templates and the context made available to them.
Why am I getting a bunch of `BadHeaderError` exceptions?
----------------------------------------------------------
Most likely, you have an error in your
:class:`~django_contact_form.forms.ContactForm`
subclass. Specifically, one or more of
:attr:`~django_contact_form.forms.ContactForm.from_email`,
:attr:`~django_contact_form.forms.ContactForm.recipient_list` or
:meth:`~django_contact_form.forms.ContactForm.subject` are returning
values which contain newlines.
As a security precaution against `email header injection attacks
`_ (which allow
spammers and other malicious users to manipulate email and potentially
cause automated systems to send mail to unintended recipients),
`Django's email-sending framework does not permit newlines in message
headers
`_.
:exc:`~django.core.mail.BadHeaderError` is the exception Django raises
when a newline is detected in a header. By default,
:meth:`~django_contact_form.forms.ContactForm.subject` will forcibly
condense the subject to a single line.
Note that this only applies to the headers of an email message; the
message body can (and usually does) contain newlines.
I found a bug or want to make an improvement!
---------------------------------------------
The canonical development repository for django-contact-form is
online at . Issues
and pull requests can both be filed there.
If you'd like to contribute to django-contact-form, that's great!
Just please remember that pull requests should include tests and
documentation for any changes made, and that following `PEP 8
`_ is mandatory. Pull
requests without documentation won't be merged, and PEP 8 style
violations or test coverage below 100% are both configured to break
the build.
I'm getting errors about "akismet" when trying to run tests?
------------------------------------------------------------
The full test suite of django-contact-form exercises all of its
functionality, including the spam-filtering
:class:`~django_contact_forms.forms.AkismetContactForm`. That class
uses `the Wordpress Akismet spam-detection service
`_ to perform spam filtering, and so requires
the Python `akismet` module to communicate with the Akismet service,
and some additional configuration (in the form of a valid Akismet API
key and associated URL).
By default, the tests for
:class:`~django_contact_forms.forms.AkismetContactForm` will be
skipped unless the required configuration (in the form of either a
pair of Django settings, or a pair of environment variables) is
detected. However, if you have supplied Akismet configuration but do
*not* have the Python `akismet` module, you will see test errors from
attempts to import `akismet`. You can resolve this by running::
pip install akismet
or (if you do not intend to use
:class:`~django_contact_forms.forms.AkismetContactForm`) by no longer
configuring the Django settings/environment variables used by Akismet.
Additionally, if the
:class:`~django_contact_forms.forms.AkismetContactForm` tests are
skipped, the default code-coverage report will fail due to the
relevant code not being exercised during the test run. django-contact-form-2.0.1/docs/forms.rst 0000664 0000000 0000000 00000021771 14245325761 0020177 0 ustar 00root root 0000000 0000000 .. _forms:
.. module:: django_contact_form.forms
Contact form classes
====================
There are two contact-form classes included in django-contact-form;
one provides all the infrastructure for a contact form, and will
usually be the base class for subclasses which want to extend or
modify functionality. The other is a subclass which adds spam
filtering to the contact form.
The ContactForm class
---------------------
.. class:: ContactForm
The base contact form class from which all contact form classes
should inherit.
If you don't need any customization, you can use this form to
provide basic contact-form functionality; it will collect name,
email address and message.
The :class:`~django_contact_form.views.ContactFormView` included
in this application knows how to work with this form and can
handle many types of subclasses as well (see below for a
discussion of the important points), so in many cases it will be
all that you need. If you'd like to use this form or a subclass of
it from one of your own views, here's how:
1. When you instantiate the form, pass the current
:class:`~django.http.HttpRequest` object as the keyword
argument `request`; this is used internally by the base
implementation, and also made available so that subclasses can
add functionality which relies on inspecting the request (such
as spam filtering).
2. To send the message, call the form's :meth:`save` method, which
accepts the keyword argument `fail_silently` and defaults it to
`False`. This argument is passed directly to Django's
:func:`~django.core.mail.send_mail` function, and allows you to
suppress or raise exceptions as needed for debugging. The
:meth:`save` method has no return value.
Other than that, treat it like any other form; validity checks and
validated data are handled normally, through the
:meth:`~django.forms.Form.is_valid` method and the
:attr:`~django.forms.Form.cleaned_data` dictionary.
Under the hood, this form uses a somewhat abstracted interface in
order to make it easier to subclass and add functionality.
The following attributes play a role in determining behavior, and
any of them can be implemented as an attribute or as a method (for
example, if you wish to have :attr:`from_email` be dynamic, you
can implement a method named :meth:`from_email` instead of setting
the attribute :attr:`from_email`).
.. attribute:: from_email
The email address (:class:`str`) to use in the `From:` header
of the message. By default, this is the value of the Django
setting :data:`~django.conf.settings.DEFAULT_FROM_EMAIL`.
.. attribute:: recipient_list
A :class:`list` of recipients for the message. By default, this
is the email addresses specified in the setting
:data:`~django.conf.settings.MANAGERS`.
.. attribute:: subject_template_name
A :class:`str`, the name of the template to use when rendering
the subject line of the message. By default, this is
`django_contact_form/contact_form_subject.txt`.
.. attribute:: template_name
A :class:`str`, the name of the template to use when rendering
the body of the message. By default, this is
`django_contact_form/contact_form.txt`.
And two methods are involved in producing the contents of the
message to send:
.. method:: message
Returns the body of the message to send. By default, this is
accomplished by rendering the template name specified in
:attr:`template_name`.
:rtype: str
.. method:: subject
Returns the subject line of the message to send. By default,
this is accomplished by rendering the template name specified
in :attr:`subject_template_name`.
:rtype: str
.. warning:: **Subject must be a single line**
The subject of an email is sent in a header (named
`Subject:`). Because email uses newlines as a separator between
headers, newlines in the subject can cause it to be interpreted
as multiple headers; this is the `header injection attack
`_. To prevent
this, :meth:`subject` will always force the subject to a single
line of text, stripping all newline characters. If you override
:meth:`subject`, be sure to either do this manually, or use
:func:`super` to call the parent implementation.
Finally, the message itself is generated by the following two
methods:
.. method:: get_message_dict
This method loops through :attr:`from_email`,
:attr:`recipient_list`, :meth:`message` and :meth:`subject`,
collecting those parts into a dictionary with keys
corresponding to the arguments to Django's `send_mail`
function, then returns the dictionary. Overriding this allows
essentially unlimited customization of how the message is
generated. Note that for compatibility, implementations which
override this should support callables for the values of
:attr:`from_email` and :attr:`recipient_list`.
:rtype: dict
.. method:: get_message_context
.. warning:: **Renamed method**
Prior to django-contact-form 2.x, this method was named
`get_context()`. It was renamed to `get_message_context()`
in django-contact-form 2.0. See :ref:`the upgrade guide
` for details.
For methods which render portions of the message using
templates (by default, :meth:`message` and :meth:`subject`),
generates the context used by those templates. The default
context will be a :class:`~django.template.RequestContext`
(using the current HTTP request, so user information is
available), plus the contents of the form's
:attr:`~django.forms.Form.cleaned_data` dictionary, and one
additional variable:
`site`
If `django.contrib.sites` is installed, the currently-active
:class:`~django.contrib.sites.models.Site` object. Otherwise,
a :class:`~django.contrib.sites.requests.RequestSite` object
generated from the request.
:rtype: dict
Meanwhile, the following attributes/methods generally should not
be overridden; doing so may interfere with functionality, may not
accomplish what you want, and generally any desired customization
can be accomplished in a more straightforward way through
overriding one of the attributes/methods listed above.
.. attribute:: request
The :class:`~django.http.HttpRequest` object representing the
current request. This is set automatically in `__init__()`, and
is used both to generate a
:class:`~django.template.RequestContext` for the templates and
to allow subclasses to engage in request-specific behavior.
.. method:: save
If the form has data and is valid, will send the email, by
calling :meth:`get_message_dict` and passing the result to
Django's :func:`~django.core.mail.send_mail` function.
Note that subclasses which override `__init__` or :meth:`save`
need to accept `*args` and `**kwargs`, and pass them via
:func:`super`, in order to preserve behavior (each of those
methods accepts at least one additional argument, and this
application expects and requires them to do so).
The Akismet (spam-filtering) contact form class
-----------------------------------------------
.. class:: AkismetContactForm
A subclass of :class:`ContactForm` which adds spam filtering, via
`the Wordpress Akismet spam-detection service
`_.
Use of this class requires you to provide configuration for the
Akismet web service; you'll need to obtain an Akismet API key, and
you'll need to associate it with the site you'll use the contact
form on. You can do this at . Once you have,
you can configure in either of two ways:
1. Put your Akismet API key in the Django setting
:data:`~django.conf.settings.AKISMET_API_KEY`, and the URL it's
associated with in the setting
:class:`~django.conf.settings.AKISMET_BLOG_URL`, or
2. Put your Akismet API key in the environment variable
`PYTHON_AKISMET_API_KEY`, and the URL it's associated with in
the environment variable `PYTHON_AKISMET_BLOG_URL`.
You will also need `the Python Akismet module
`_ to communicate with the Akismet
web service. You can install it by running `pip install akismet`,
or django-contact-form can install it automatically for you if you
run `pip install django-contact-form[akismet]`.
Once you have an Akismet API key and URL configured, and the
`akismet` module installed, you can drop in
:class:`AkismetContactForm` anywhere you would have used
:class:`ContactForm`. A URLconf is provided in django-contact-form,
at `django_contact_form.akismet_urls`, which will correctly
configure :class:`AkismetContactForm` for you.
django-contact-form-2.0.1/docs/index.rst 0000664 0000000 0000000 00000001543 14245325761 0020153 0 ustar 00root root 0000000 0000000 .. _index:
django-contact-form |release|
=============================
django-contact-form provides customizable contact-form functionality
for `Django `_-powered Web sites.
Basic functionality (collecting a name, email address and message) can
be achieved out of the box by setting up a few templates and adding
one line to your site's root URLconf:
.. code-block:: python
path('contact/', include('django_contact_form.urls')),
For notes on getting started quickly, and on how to customize
django-contact-form's behavior, read through the full documentation
below.
.. toctree::
:caption: Installation and configuration
:maxdepth: 1
install
quickstart
.. toctree::
:caption: For developers
:maxdepth: 1
forms
views
.. toctree::
:caption: Other documentation
:maxdepth: 1
upgrade
faq django-contact-form-2.0.1/docs/install.rst 0000664 0000000 0000000 00000004111 14245325761 0020504 0 ustar 00root root 0000000 0000000 .. _install:
Installation guide
==================
The |release| release of django-contact-form supports Django 3.2 and
4.0 on Python 3.7 (Django 3.2 only), 3.8, 3.9, and 3.10. Note that
Django 3.2's support for Python 3.10 was added in Django 3.2.9, so you
may experience issues with Python 3.10 and earlier Django 3.2
versions.
Normal installation
-------------------
The preferred method of installing django-contact-form is via `pip`,
the standard Python package-installation tool. If you don't have
`pip`, instructions are available for `how to obtain and install it
`_. If you're using a
supported version of Python, `pip` should have come bundled with your
installation of Python.
Once you have `pip`, type::
pip install django-contact-form
If you plan to use the included spam-filtering contact form class,
:class:`~contact_form.forms.AkismetContactForm`, you will also need
`the Python akismet module `_. You
can manually install it via `pip install akismet`, or tell
django-contact-form to install it for you, by running::
pip install django-contact-form[akismet]
If you don't have a copy of a compatible version of Django, installing
django-contact-form will also automatically install one for you.
Installing from a source checkout
---------------------------------
If you want to work on django-contact-form, you can obtain a source
checkout.
The development repository for django-contact-form is at
. If you have `git
`_ installed, you can obtain a copy of the
repository by typing::
git clone https://github.com/ubernostrum/django-contact-form.git
From there, you can use git commands to check out the specific
revision you want, and perform an "editable" install (allowing you to
change code as you work on it) by typing::
pip install -e .
Next steps
----------
To get up and running quickly, check out :ref:`the quick start guide
`. For full documentation, see :ref:`the documentation
index `. django-contact-form-2.0.1/docs/make.bat 0000664 0000000 0000000 00000012002 14245325761 0017707 0 ustar 00root root 0000000 0000000 @ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^` where ^ is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-contact-form.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-contact-form.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
django-contact-form-2.0.1/docs/quickstart.rst 0000664 0000000 0000000 00000013624 14245325761 0021241 0 ustar 00root root 0000000 0000000 .. _quickstart:
Quick start guide
=================
First you'll need to have Django and django-contact-form
installed; for details on that, see :ref:`the installation guide
`.
Once that's done, you can start setting up django-contact-form. First,
add `'django_contact_form'` to your
:data:`~django.conf.settings.INSTALLED_APPS` setting. Then, you can
begin configuring.
URL configuration
-----------------
The quickest way to set up the views in django-contact-form is to use
the provided URLconf, found at `django_contact_form.urls`. You can
include it wherever you like in your site's URL configuration; for
example, to have it live at the URL `/contact/`:
.. code-block:: python
from django.urls import include, path
urlpatterns = [
# ... other URL patterns for your site ...
path('contact/', include('django_contact_form.urls')),
]
If you'll be using a custom form class, you'll need to manually set up
your URLs so you can tell django-contact-form about your form
class. For example:
.. code-block:: python
from django.urls import include, path
from django.views.generic import TemplateView
from django_contact_form.views import ContactFormView
from yourapp.forms import YourCustomFormClass
urlpatterns = [
# ... other URL patterns for your site ...
path('contact/',
ContactFormView.as_view(
form_class=YourCustomFormClass
),
name='django_contact_form'),
path('contact/sent/',
TemplateView.as_view(
template_name='django_contact_form/contact_form_sent.html'
),
name='django_contact_form_sent'),
]
.. important:: **Where to put custom forms and views**
When writing a custom form class (or custom
:class:`~django_contact_form.views.ContactFormView` subclass), **don't**
put your custom code inside django-contact-form. Instead, put your
custom code in the appropriate place (a `forms.py` or `views.py`
file) in an application you've written.
Required templates
------------------
The two views above will need several templates to be created.
`django_contact_form/contact_form.html`
```````````````````````````````````````
This is used to display the contact form. It has a
:class:`~django.template.RequestContext` (so any context processors
will be applied), and also provides the form instance as the context
variable `form`.
`django_contact_form/contact_form_sent.html`
````````````````````````````````````````````
This is used after a successful form submission, to let the user know
their message has been sent. It has a
:class:`~django.template.RequestContext`, but provides no additional
context variables of its own.
`django_contact_form/contact_form.txt`
``````````````````````````````````````
Used to render the subject of the email. Will receive a
:class:`~django.template.RequestContext` with the following additional
variables:
`body`
The message the user typed.
`email`
The email address the user supplied.
`name`
The name the user supplied.
`site`
The current site. Either a
:class:`~django.contrib.sites.models.Site` or
:class:`~django.contrib.sites.requests.RequestSite` instance,
depending on whether `Django's sites framework
`_ is
installed).
`django_contact_form/contact_form_subject.txt`
``````````````````````````````````````````````
Used to render the subject of the email. Will receive a
:class:`~django.template.RequestContext` with the following additional
variables:
`body`
The message the user typed.
`email`
The email address the user supplied.
`name`
The name the user supplied.
`site`
The current site. Either a
:class:`~django.contrib.sites.models.Site` or
:class:`~django.contrib.sites.requests.RequestSite` instance,
depending on whether `Django's sites framework
`_ is
installed).
.. warning:: **Subject must be a single line**
In order to prevent `header injection attacks
`_, the subject
*must* be only a single line of text, and Django's email framework
will reject any attempt to send an email with a multi-line
subject. So it's a good idea to ensure your
`contact_form_subject.txt` template only produces a single line of
output when rendered; as a precaution, however, django-contact-form
will, by default, condense the output of this template to a single
line.
Using a spam-filtering contact form
-----------------------------------
Spam filtering is a common desire for contact forms, due to the large
amount of spam they can attract. There is a spam-filtering contact
form class included in django-contact-form:
:class:`~django_contact_form.forms.AkismetContactForm`, which uses
`the Wordpress Akismet spam-detection service
`_.
To use this form, you will need to do the following things:
1. Install the Python `akismet` module to allow django-contact-form
to communicate with the Akismet service. You can do this via `pip
install akismet`, or as you install django-contact-form via `pip
install django-contact-form[akismet]`.
2. Obtain an Akismet API key from , and
associate it with the URL of your site.
3. Supply the API key and URL for django-contact-form to use. You can
either place them in the Django settings
:data:`~django.conf.settings.AKISMET_API_KEY` and
:data:`~django.conf.settings.AKISMET_BLOG_URL`, or in the
environment variables `PYTHON_AKISMET_API_KEY` and
`PYTHON_AKISMET_BLOG_URL`.
Then you can replace the suggested URLconf above with the following:
.. code-block:: python
from django.urls import include, path
urlpatterns = [
# ... other URL patterns for your site ...
path('contact/', include('django_contact_form.akismet_urls')),
]
django-contact-form-2.0.1/docs/spelling_wordlist.txt 0000664 0000000 0000000 00000000153 14245325761 0022613 0 ustar 00root root 0000000 0000000 Akismet
akismet
callables
config
customizable
dev
django
multi
online
spam
spammers
subclasses
subclassing
django-contact-form-2.0.1/docs/upgrade.rst 0000664 0000000 0000000 00000004417 14245325761 0020476 0 ustar 00root root 0000000 0000000 .. _upgrade:
Upgrading from previous versions
================================
The current release series of django-contact-form is the 2.x series,
which is not backwards-compatible with the django-contact-form 1.x
release series.
Changes between django-contact-form 1.x and 2.x
-----------------------------------------------
Module renaming
~~~~~~~~~~~~~~~
Prior to 2.x, django-contact-form installed a Python module named
`contact_form`. To avoid silent incompatibilities, and to conform to
more recent best practices, django-contact-form 2.x now installs a
module named `django_contact_form`. Attempts to import from the
`contact_form` module will immediately fail with :exc:`ImportError`.
Many installations will be able to adapt by replacing references to
`contact_form` with references to `django_contact_form`.
Template directory renamed
~~~~~~~~~~~~~~~~~~~~~~~~~~
Similar to the module renaming above, the name of the default
directory in which django-contact-form looks for templates has changed
from `contact_form/` to `django_contact_form/`.
.. _renamed-get-context:
Method renamed: get_context() -> get_message_context()
``````````````````````````````````````````````````````
Prior to 2.x, :class:`~django_contact_form.forms.ContactForm` provided
a method named `get_context()` which was used to generate the template
context from which the message would be rendered. However, Django 4.0
introduced `a new template-based system for rendering forms
`_,
and as a result :class:`django.forms.Form` now has a method named
:meth:`~django.forms.Form.get_context`.
To resolve this conflict with Django's own base form class, the method
in django-contact-form has been renamed to
:meth:`~django_contact_form.forms.ContactForm.get_message_context`,
which hopefully will not be adopted by any future version of Django's
own forms system.
If you were previously overriding `get_context()`, you should rename
your overridden method to
:meth:`~django_contact_form.forms.ContactForm.get_message_context` to
ensure it is still called properly. If you have other code which
called `get_context()`, you should update any such references to call
:meth:`~django_contact_form.forms.ContactForm.get_message_context`
instead. django-contact-form-2.0.1/docs/views.rst 0000664 0000000 0000000 00000006177 14245325761 0020211 0 ustar 00root root 0000000 0000000 .. _views:
.. module:: django_contact_form.views
Built-in views
==============
.. class:: ContactFormView
The base view class from which most custom contact-form views
should inherit. If you don't need any custom functionality, and
are content with the default
:class:`~django_contact_form.forms.ContactForm` class, you can
also use it as-is (and the provided URLConf,
`django_contact_form.urls`, does exactly this).
This is a subclass of Django's
:class:`~django.views.generic.edit.FormView`, so refer to the
Django documentation for a list of attributes/methods which can be
overridden to customize behavior.
One non-standard attribute is defined here:
.. attribute:: recipient_list
The list of email addresses to send mail to. If not specified,
defaults to the
:attr:`~django_contact_form.forms.ContactForm.recipient_list` of the
form.
Additionally, the following standard (from
:class:`~django.views.generic.edit.FormView`) methods and
attributes are commonly useful to override (all attributes below
can also be passed to
:meth:`~django.views.generic.base.View.as_view()` in the URLconf,
permitting customization without the need to write a full custom
subclass of :class:`ContactFormView`):
.. attribute:: form_class
The form class to use. By default, will be
:class:`~django_contact_form.forms.ContactForm`. This can also
be overridden as a method named
:meth:`~django.views.generic.edit.FormMixin.form_class`; this
permits, for example, per-request customization (by inspecting
attributes of `self.request`).
.. attribute:: template_name
A :class:`str`, the template to use when rendering the form. By
default, will be `django_contact_form/contact_form.html`.
.. method:: get_success_url
The URL to redirect to after successful form submission. Can be
a hard-coded string, the string resulting from calling Django's
:func:`~django.urls.reverse` helper, or the lazy object
produced by Django's :func:`~django.urls.reverse_lazy`
helper. Default value is the result of calling
:func:`~django.urls.reverse_lazy` with the URL name
`'django_contact_form_sent'`.
:rtype: str
.. method:: get_form_kwargs
Returns additional keyword arguments (as a dictionary) to pass
to the form class on initialization.
By default, this will return a dictionary containing the
current :class:`~django.http.HttpRequest` (as the key
`request`) and, if :attr:`~ContactFormView.recipient_list` was
defined, its value (as the key `recipient_list`).
.. warning:: If you override :meth:`get_form_kwargs`, you
**must** ensure that, at the very least, the keyword argument
`request` is still provided, or
:class:`~django_contact_form.forms.ContactForm` initialization
will raise :exc:`TypeError`. The easiest approach is to use
:func:`super` to call the base implementation in
:class:`ContactFormView`, and modify the dictionary it returns.
:rtype: dict
django-contact-form-2.0.1/runtests.py 0000664 0000000 0000000 00000005054 14245325761 0017624 0 ustar 00root root 0000000 0000000 """
A standalone test runner script, configuring the minimum settings
required for tests to execute.
Re-use at your own risk: many Django applications will require full
settings and/or templates in order to execute their tests.
"""
import os
import sys
from django.utils.crypto import get_random_string
APP_DIR = os.path.abspath(os.path.dirname(__file__))
# Minimum settings required for django-contact-form to work.
SETTINGS_DICT = {
"BASE_DIR": APP_DIR,
"INSTALLED_APPS": (
"django_contact_form",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sites",
),
"ROOT_URLCONF": "django_contact_form.urls",
"DATABASES": {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(APP_DIR, "db.sqlite3"),
}
},
"MIDDLEWARE": (
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
),
"SITE_ID": 1,
"DEFAULT_FROM_EMAIL": "contact@example.com",
"MANAGERS": [("Manager", "noreply@example.com")],
"SECRET_KEY": get_random_string(12),
"TEMPLATES": [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(APP_DIR, "tests/templates")],
"OPTIONS": {
"context_processors": [
"django.contrib.auth.context_processors.auth",
"django.template.context_processors.debug",
"django.template.context_processors.i18n",
"django.template.context_processors.media",
"django.template.context_processors.static",
"django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
]
},
}
],
}
def run_tests():
# Making Django run this way is a two-step process. First, call
# settings.configure() to give Django settings to work with:
from django.conf import settings
settings.configure(**SETTINGS_DICT)
# Then, call django.setup() to initialize the application cache
# and other bits:
import django
django.setup()
# Now we instantiate a test runner...
from django.test.utils import get_runner
TestRunner = get_runner(settings)
# And then we run tests and return the results.
test_runner = TestRunner(verbosity=2, interactive=True)
failures = test_runner.run_tests(["tests"])
sys.exit(bool(failures))
if __name__ == "__main__":
run_tests()
django-contact-form-2.0.1/setup.cfg 0000664 0000000 0000000 00000000546 14245325761 0017205 0 ustar 00root root 0000000 0000000 [coverage:report]
fail_under = 100
exclude_lines =
pragma: no cover
def __str__
raise NotImplementedError
[flake8]
extend-ignore = E203
max-complexity = 10
max-line-length = 88
[isort]
known_first_party = django_contact_form
known_third_party = django
profile = black
[check-manifest]
ignore =
__pycache__
*.pyc
ignore-bad-ideas =
*.mo
django-contact-form-2.0.1/setup.py 0000664 0000000 0000000 00000002550 14245325761 0017073 0 ustar 00root root 0000000 0000000 import os
from setuptools import find_packages, setup
setup(
name="django-contact-form",
version="2.0.1",
zip_safe=False, # eggs are the devil.
description="A generic contact-form application for Django",
long_description=open(os.path.join(os.path.dirname(__file__), "README.rst")).read(),
author="James Bennett",
author_email="james@b-list.org",
url="https://github.com/ubernostrum/django-contact-form/",
include_package_data=True,
package_dir={"": "src"},
packages=find_packages("src"),
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 3.2",
"Framework :: Django :: 4.0",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Utilities",
],
keywords=["django", "email", "contact-form"],
python_requires=">=3.7",
install_requires=["Django>=3.2"],
extras_require={"akismet": ["akismet"]},
)
django-contact-form-2.0.1/src/ 0000775 0000000 0000000 00000000000 14245325761 0016146 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/ 0000775 0000000 0000000 00000000000 14245325761 0022146 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/__init__.py 0000664 0000000 0000000 00000000000 14245325761 0024245 0 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/akismet_urls.py 0000664 0000000 0000000 00000001304 14245325761 0025220 0 ustar 00root root 0000000 0000000 """
Example URLConf for a contact form with Akismet spam filtering.
If all you want is the basic contact-form plus spam filtering,
include this URLConf somewhere in your URL hierarchy (for example, at
``/contact/``).
"""
from django.urls import path
from django.views.generic import TemplateView
from .forms import AkismetContactForm
from .views import ContactFormView
urlpatterns = [
path(
"",
ContactFormView.as_view(form_class=AkismetContactForm),
name="django_contact_form",
),
path(
"sent/",
TemplateView.as_view(
template_name="django_contact_form/contact_form_sent.html"
),
name="django_contact_form_sent",
),
]
django-contact-form-2.0.1/src/django_contact_form/forms.py 0000664 0000000 0000000 00000012014 14245325761 0023644 0 ustar 00root root 0000000 0000000 """
A base contact form for allowing users to send email messages through
a web interface.
"""
from django import forms
from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
from django.template import loader
from django.utils.translation import gettext_lazy as _
class ContactForm(forms.Form):
"""
The base contact form class from which all contact form classes
should inherit.
"""
name = forms.CharField(max_length=100, label=_("Your name"))
email = forms.EmailField(max_length=200, label=_("Your email address"))
body = forms.CharField(widget=forms.Textarea, label=_("Your message"))
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [mail_tuple[1] for mail_tuple in settings.MANAGERS]
subject_template_name = "django_contact_form/contact_form_subject.txt"
template_name = "django_contact_form/contact_form.txt"
def __init__(
self, data=None, files=None, request=None, recipient_list=None, *args, **kwargs
):
if request is None:
raise TypeError("Keyword argument 'request' must be supplied")
self.request = request
if recipient_list is not None:
self.recipient_list = recipient_list
super().__init__(data=data, files=files, *args, **kwargs)
def message(self):
"""
Render the body of the message to a string.
"""
template_name = (
self.template_name() if callable(self.template_name) else self.template_name
)
return loader.render_to_string(
template_name, self.get_message_context(), request=self.request
)
def subject(self):
"""
Render the subject of the message to a string.
"""
template_name = (
self.subject_template_name()
if callable(self.subject_template_name)
else self.subject_template_name
)
subject = loader.render_to_string(
template_name, self.get_message_context(), request=self.request
)
return "".join(subject.splitlines())
def get_message_context(self):
"""
Return the context used to render the templates for the email
subject and body.
By default, this context includes:
* All of the validated values in the form, as variables of the
same names as their fields.
* The current ``Site`` object, as the variable ``site``.
* Any additional variables added by context processors (this
will be a ``RequestContext``).
"""
if not self.is_valid():
raise ValueError("Cannot generate Context from invalid contact form")
return dict(self.cleaned_data, site=get_current_site(self.request))
def get_message_dict(self):
"""
Generate the various parts of the message and return them in a
dictionary, suitable for passing directly as keyword arguments
to ``django.core.mail.send_mail()``.
By default, the following values are returned:
* ``from_email``
* ``message``
* ``recipient_list``
* ``subject``
"""
if not self.is_valid():
raise ValueError("Message cannot be sent from invalid contact form")
message_dict = {}
for message_part in ("from_email", "message", "recipient_list", "subject"):
attr = getattr(self, message_part)
message_dict[message_part] = attr() if callable(attr) else attr
return message_dict
def save(self, fail_silently=False):
"""
Build and send the email message.
"""
send_mail(fail_silently=fail_silently, **self.get_message_dict())
class AkismetContactForm(ContactForm):
"""
Contact form which doesn't add any extra fields, but does add an
Akismet spam check to the validation routine.
Requires the Python Akismet library, and two configuration
parameters: an Akismet API key and the URL the key is associated
with. These can be supplied either as the settings AKISMET_API_KEY
and AKISMET_BLOG_URL, or the environment variables
PYTHON_AKISMET_API_KEY and PYTHON_AKISMET_BLOG_URL.
"""
SPAM_MESSAGE = _("Your message was classified as spam.")
def clean_body(self):
from akismet import Akismet
akismet_api = Akismet(
key=getattr(settings, "AKISMET_API_KEY", None),
blog_url=getattr(settings, "AKISMET_BLOG_URL", None),
)
akismet_kwargs = {
"user_ip": self.request.META["REMOTE_ADDR"],
"user_agent": self.request.META.get("HTTP_USER_AGENT"),
"comment_author": self.cleaned_data.get("name"),
"comment_author_email": self.cleaned_data.get("email"),
"comment_content": self.cleaned_data["body"],
"comment_type": "contact-form",
}
if akismet_api.comment_check(**akismet_kwargs):
raise forms.ValidationError(self.SPAM_MESSAGE)
return self.cleaned_data["body"]
django-contact-form-2.0.1/src/django_contact_form/locale/ 0000775 0000000 0000000 00000000000 14245325761 0023405 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/locale/da/ 0000775 0000000 0000000 00000000000 14245325761 0023771 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/locale/da/LC_MESSAGES/ 0000775 0000000 0000000 00000000000 14245325761 0025556 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/locale/da/LC_MESSAGES/django.po 0000664 0000000 0000000 00000001773 14245325761 0027370 0 ustar 00root root 0000000 0000000 # SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR , YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-23 18:03+0100\n"
"PO-Revision-Date: 2020-01-23 18:00+0050\n"
"Last-Translator: b'Anonymous User '\n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Translated-Using: django-rosetta 0.9.0\n"
#: contact_form/forms.py:27
msgid "Your name"
msgstr "Dit navn"
#: contact_form/forms.py:28
msgid "Your email address"
msgstr "Din emailadresse"
#: contact_form/forms.py:29
msgid "Your message"
msgstr "Din besked"
#: contact_form/forms.py:148
msgid "Your message was classified as spam."
msgstr "Din besked var klassifiseret som spam."
django-contact-form-2.0.1/src/django_contact_form/locale/de/ 0000775 0000000 0000000 00000000000 14245325761 0023775 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/locale/de/LC_MESSAGES/ 0000775 0000000 0000000 00000000000 14245325761 0025562 5 ustar 00root root 0000000 0000000 django-contact-form-2.0.1/src/django_contact_form/locale/de/LC_MESSAGES/django.mo 0000664 0000000 0000000 00000001024 14245325761 0027356 0 ustar 00root root 0000000 0000000 <