mirror of https://github.com/QingdaoU/Spirit.git
Feature/install (#193)
* add yarn * spirit startproject command * readme usage * remove example from travis * readme run tests * exit instead of raise * remove yarn.lock * core.conf settings * django.conf.settings -> core.conf.settings everywhere * editorconfig makefiles * docs * core.conf.defaults docs * installation docs * upgrade docs * update history * spirit.settings deprecation warning * update readme
This commit is contained in:
parent
c2f9ed3a49
commit
6dc6c87a04
|
@ -24,3 +24,8 @@ indent_size = 2
|
|||
[*.scss]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Override for Makefile
|
||||
[{Makefile, makefile, GNUmakefile}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
|
|
@ -22,7 +22,6 @@ __pycache__/
|
|||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
bin/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
|
|
|
@ -18,7 +18,8 @@ install:
|
|||
- pip install coveralls pep8==1.5.7 flake8
|
||||
script:
|
||||
- flake8 --exit-zero
|
||||
- ./runtests.py example
|
||||
- python setup.py build
|
||||
- python ./spirit/extra/bin/spirit.py startproject project
|
||||
- coverage run --source=. runtests.py
|
||||
after_success:
|
||||
- coveralls
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
* Remove deprecated `topic_poll` app
|
||||
* Remove deprecated (since v0.2) `spirit_user.User` (PR #141),
|
||||
read the wiki or the PR for a workaround
|
||||
* Deprecates `spirit.settings`. It will be removed in future releases
|
||||
|
||||
0.4.8
|
||||
==================
|
||||
|
|
|
@ -6,9 +6,6 @@ include requirements.txt
|
|||
|
||||
graft spirit
|
||||
|
||||
prune example
|
||||
prune spirit/search/whoosh_index
|
||||
|
||||
global-exclude __pycache__
|
||||
global-exclude *.py[co]
|
||||
global-exclude .git*
|
||||
|
|
7
Makefile
7
Makefile
|
@ -1,5 +1,8 @@
|
|||
clean:
|
||||
rm -fr dist/ *.egg-info/
|
||||
rm -fr dist/ build/ *.egg-info/
|
||||
|
||||
docs:
|
||||
cd docs && make clean && make html
|
||||
|
||||
test:
|
||||
python runtests.py
|
||||
|
@ -10,4 +13,4 @@ sdist: test clean
|
|||
release: test clean
|
||||
python setup.py sdist upload
|
||||
|
||||
.PHONY: clean test sdist release
|
||||
.PHONY: clean test sdist release docs
|
||||
|
|
26
README.md
26
README.md
|
@ -15,20 +15,30 @@ To see it in action, please visit [The Spirit Project](http://spirit-project.com
|
|||
* Django 1.8 LTS (recommended), 1.9 and 1.10
|
||||
* PostgreSQL (recommended), MySQL, Oracle Database and SQLite
|
||||
|
||||
## Installing (Advanced)
|
||||
## Usage
|
||||
|
||||
Check out the [example project](https://github.com/nitely/Spirit/tree/master/example).
|
||||
```python
|
||||
pip install django-spirit
|
||||
spirit startproject mysite
|
||||
cd mysite
|
||||
python manage.py spiritinstall
|
||||
python manage.py createsuperuser
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
## Upgrading
|
||||
Visit [http://127.0.0.1:8000](http://127.0.0.1:8000)
|
||||
|
||||
Detailed upgrade instructions are listed in [Upgrading Spirit](https://github.com/nitely/Spirit/wiki/Upgrading)
|
||||
For detailed installation and setup docs, see [spirit.readthedocs.io](http://spirit.readthedocs.io/en/latest/)
|
||||
|
||||
## Documentation
|
||||
|
||||
Docs can be found at [spirit.readthedocs.io](http://spirit.readthedocs.io/en/latest/)
|
||||
|
||||
## Testing
|
||||
|
||||
The `runtests.py` script enable you to run the test suite of spirit.
|
||||
|
||||
- Type `./runtests.py` to run the test suite using the settings from the `spirit` folder.
|
||||
- Type `./runtests.py example` to run the test suite using the settings from the `example` folder.
|
||||
```python
|
||||
$ python runtests.py
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = python -msphinx
|
||||
SPHINXPROJ = Spirit
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,4 @@
|
|||
Changelog
|
||||
*********
|
||||
|
||||
.. include:: ../HISTORY.md
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Spirit documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Sep 24 08:30:18 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
add_module_names = False
|
||||
version = __import__('spirit').__version__
|
||||
release = version
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.githubpages']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Spirit'
|
||||
copyright = '2017, Esteban Castro Borsani'
|
||||
author = 'Esteban Castro Borsani'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'about.html',
|
||||
'navigation.html',
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
'donate.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Spiritdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'Spirit.tex', 'Spirit Documentation',
|
||||
'Esteban Castro Borsani', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'spirit', 'Spirit Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'Spirit', 'Spirit Documentation',
|
||||
author, 'Spirit', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Contributors
|
||||
************
|
||||
|
||||
.. include:: ../AUTHORS.md
|
|
@ -0,0 +1,27 @@
|
|||
.. Spirit documentation master file, created by
|
||||
sphinx-quickstart on Sun Sep 24 08:30:18 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Spirit's docs
|
||||
=============
|
||||
|
||||
User’s Guide
|
||||
------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
installation
|
||||
upgrade
|
||||
settings
|
||||
|
||||
Additional Notes
|
||||
----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
contributors
|
||||
changelog
|
||||
license
|
|
@ -0,0 +1,55 @@
|
|||
.. _installation:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
* Python 2.7, 3.4 and 3.5 (recommended)
|
||||
* Django 1.8 LTS (recommended), 1.9 and 1.10
|
||||
* PostgreSQL (recommended), MySQL, Oracle Database and SQLite
|
||||
|
||||
Get started
|
||||
-----------
|
||||
|
||||
Latest version can be installed through pip::
|
||||
|
||||
1. Install Spirit::
|
||||
|
||||
pip install django-spirit
|
||||
|
||||
2. Start your site::
|
||||
|
||||
spirit startproject mysite
|
||||
|
||||
3. Set up the database::
|
||||
|
||||
cd mysite
|
||||
python manage.py spiritinstall
|
||||
|
||||
4. Create an administrator account::
|
||||
|
||||
python manage.py createsuperuser
|
||||
python manage.py runserver
|
||||
|
||||
Now sign in at http://127.0.0.1:8000/
|
||||
|
||||
Side notes
|
||||
----------
|
||||
|
||||
This will run using the `developer` settings.
|
||||
Running a production site is out of the scope
|
||||
of this documentation. However there are many
|
||||
guides about running a Django site out there.
|
||||
|
||||
Here are some hints:
|
||||
|
||||
* On production, create a ``prod_local.py``,
|
||||
import the production settings ``from .prod import *``
|
||||
and override settings such as ``DATABASES`` and ``ALLOWED_HOSTS``.
|
||||
* Gunicorn and Nginx are a common way of running Python sites.
|
||||
* An email server is required. There are self-hosted ones (ie: `exim <http://www.exim.org/>`_),
|
||||
and managed ones (ie: `Postmark <https://postmarkapp.com/>`_).
|
||||
* A search engine is required. `Woosh <https://bitbucket.org/mchaput/whoosh/wiki/Home>`_
|
||||
comes configured by default, however is quite slow. A better choice may be elastic-search.
|
|
@ -0,0 +1,4 @@
|
|||
License
|
||||
=======
|
||||
|
||||
.. include:: ../LICENSE
|
|
@ -0,0 +1,36 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=python -msphinx
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=Spirit
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
|
||||
echo.then set the SPHINXBUILD environment variable to point to the full
|
||||
echo.path of the 'sphinx-build' executable. Alternatively you may add the
|
||||
echo.Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
|
@ -0,0 +1,8 @@
|
|||
.. _settings:
|
||||
|
||||
Settings
|
||||
========
|
||||
|
||||
.. automodule:: spirit.core.conf.defaults
|
||||
:members:
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
.. _upgrade:
|
||||
|
||||
Upgrade
|
||||
=======
|
||||
|
||||
.. Note::
|
||||
Upgrade steps for older versions can be found at the
|
||||
`Wiki <https://github.com/nitely/Spirit/wiki/Upgrading>`_
|
||||
|
||||
.. Warning::
|
||||
Make a database backup before upgrading to avoid data loss,
|
||||
you have been warned. Use the ``pg_dump`` command on PostgreSQL or
|
||||
``mysqldump`` on MySQL. You can also create a backup running python
|
||||
``python manage.py dumpdata --indent=4 > database.json``.
|
||||
You may want to backup the media folder as well.
|
||||
|
||||
.. Note::
|
||||
Make sure to check the changelog for every
|
||||
patch version of the upgrading target and
|
||||
make changes accordingly
|
||||
|
||||
From v0.4.x to v0.5.x
|
||||
---------------------
|
||||
|
||||
Starting from spirit v0.5, cloning the repo is no longer encouraged. Pip it instead.
|
||||
|
||||
Installation::
|
||||
|
||||
pip install -I django-spirit==0.5.x
|
||||
# Replace the x by the latest patch version
|
||||
|
||||
Migration::
|
||||
|
||||
python manage.py spiritupgrade
|
||||
# this will run ``migrate``, ``rebuild_index`` and ``collectstatic``
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#Running the example application
|
||||
|
||||
Assuming you use virtualenv, follow these steps to download and run the
|
||||
Spirit example application in this directory:
|
||||
|
||||
|
||||
$ git clone https://github.com/nitely/Spirit.git
|
||||
$ cd Spirit
|
||||
$ virtualenv venv
|
||||
$ source ./venv/bin/activate
|
||||
$ pip install .
|
||||
$ cd example
|
||||
$ python manage.py spiritinstall
|
||||
$ python manage.py runserver
|
||||
|
||||
Visit http://127.0.0.1:8000/
|
||||
|
||||
> This will run using the *developer* settings,
|
||||
> which are not suitable for production environments.
|
||||
|
||||
|
||||
> On production, you should create a `prod_local.py`,
|
||||
> import the production settings `from .prod import *`
|
||||
> and overwrite settings such as `SECRET_KEY`, `DATABASES` and `ALLOWED_HOSTS`.
|
||||
>
|
||||
> You should run Spirit on a real web server. ie: gunicorn + Nginx.
|
||||
|
||||
|
||||
> An email server is required, you can host your own (ie: [exim](http://www.exim.org/)),
|
||||
> or hire an external service provider (ie: [Mandrill](http://mandrill.com/)).
|
||||
|
||||
|
||||
> You will need to setup a search engine,
|
||||
> Spirit is configured to work with [Woosh](https://bitbucket.org/mchaput/whoosh/wiki/Home) by default.
|
||||
|
|
@ -1 +0,0 @@
|
|||
__author__ = 'Admin'
|
|
@ -1,116 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Django settings for running the example of spirit app
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from spirit.settings import *
|
||||
|
||||
# You may override or extend spirit settings below...
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
|
||||
# Application definition
|
||||
|
||||
# This will be the default in next version
|
||||
ST_RATELIMIT_CACHE = 'st_rate_limit'
|
||||
|
||||
# Extend the Spirit installed apps.
|
||||
# Check out the spirit.settings.py so you do not end up with duplicated apps.
|
||||
INSTALLED_APPS.extend([
|
||||
# 'my_app1',
|
||||
# 'my_app2',
|
||||
])
|
||||
|
||||
# same here, check out the spirit.settings.py
|
||||
MIDDLEWARE_CLASSES.extend([
|
||||
# 'my_middleware1',
|
||||
# 'my_middleware2',
|
||||
])
|
||||
|
||||
# same here
|
||||
TEMPLATES[0]['OPTIONS']['context_processors'].extend([
|
||||
# 'my_template_proc1',
|
||||
# 'my_template_proc2',
|
||||
])
|
||||
|
||||
# same here (we update the Spirit caches)
|
||||
CACHES.update({
|
||||
# 'default': {
|
||||
# 'BACKEND': 'my.backend.path',
|
||||
# },
|
||||
})
|
||||
|
||||
|
||||
ROOT_URLCONF = 'project.urls'
|
||||
|
||||
WSGI_APPLICATION = 'project.wsgi.application'
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.6/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.6/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
|
||||
# Send an email to the site admins
|
||||
# on error when DEBUG=False,
|
||||
# log to console on error always.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
'filters': ['require_debug_false'],
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
'file': {
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': os.path.join(BASE_DIR, 'django.log'),
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'': {
|
||||
'handlers': ['console', 'mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['console', 'mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# THIS IS FOR DEVELOPMENT ENVIRONMENT
|
||||
# DO NOT USE IT IN PRODUCTION
|
||||
|
||||
# This is used to test settings and urls from example directory
|
||||
# with `./runtests.py example`
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .base import *
|
||||
|
||||
SECRET_KEY = "TEST"
|
||||
|
||||
INSTALLED_APPS.extend([
|
||||
'spirit.core.tests',
|
||||
])
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db_test.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
ROOT_URLCONF = 'example.project.urls'
|
||||
|
||||
PASSWORD_HASHERS = [
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
]
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media_test')
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static_test')
|
|
@ -1,5 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
application = get_wsgi_application()
|
14
runtests.py
14
runtests.py
|
@ -11,14 +11,7 @@ import django
|
|||
from django.test.runner import DiscoverRunner
|
||||
|
||||
|
||||
EXAMPLE = 'example' in sys.argv
|
||||
|
||||
if EXAMPLE:
|
||||
# Run tests with example settings
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'example.project.settings.test' # pragma: no cover
|
||||
else:
|
||||
# Run tests with tests settings
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'spirit.settings_tests'
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.project.settings.test'
|
||||
|
||||
|
||||
def log_warnings():
|
||||
|
@ -28,8 +21,9 @@ def log_warnings():
|
|||
|
||||
|
||||
def run_tests():
|
||||
sys.stdout.write("\nRunning spirit test suite, using settings %(settings)r\n\n"
|
||||
% {"settings": os.environ['DJANGO_SETTINGS_MODULE'], })
|
||||
sys.stdout.write(
|
||||
"\nRunning spirit test suite, using settings %(settings)r\n\n" %
|
||||
{"settings": os.environ['DJANGO_SETTINGS_MODULE']})
|
||||
test_runner = DiscoverRunner()
|
||||
failures = test_runner.run_tests([])
|
||||
sys.exit(failures)
|
||||
|
|
4
setup.py
4
setup.py
|
@ -31,6 +31,10 @@ setup(
|
|||
url='http://spirit-project.com/',
|
||||
packages=find_packages(),
|
||||
test_suite="runtests.start",
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
spirit=spirit.extra.bin.spirit:main
|
||||
""",
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=REQUIREMENTS,
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def default_categories(apps, schema_editor):
|
||||
from ...core.conf import settings
|
||||
|
||||
Category = apps.get_model("spirit_category", "Category")
|
||||
|
||||
if not Category.objects.filter(pk=settings.ST_TOPIC_PRIVATE_CATEGORY_PK).exists():
|
||||
|
|
|
@ -5,11 +5,11 @@ from __future__ import unicode_literals
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from .managers import CategoryQuerySet
|
||||
from ..core.conf import settings
|
||||
from ..core.utils.models import AutoSlugField
|
||||
from .managers import CategoryQuerySet
|
||||
|
||||
|
||||
class Category(models.Model):
|
||||
|
|
|
@ -7,10 +7,10 @@ import datetime
|
|||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
||||
from djconfig.utils import override_djconfig
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core.tests import utils
|
||||
from ..topic.models import Topic
|
||||
from ..comment.bookmark.models import CommentBookmark
|
||||
|
|
|
@ -4,10 +4,10 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from djconfig import config
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...core.utils import paginator
|
||||
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from ...core.conf import settings
|
||||
|
||||
|
||||
REASON_CHOICES = (
|
||||
(0, _("Spam")),
|
||||
|
|
|
@ -8,12 +8,12 @@ import logging
|
|||
import magic
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import smart_bytes
|
||||
from django.core.files.uploadedfile import TemporaryUploadedFile
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core import utils
|
||||
from ..core.utils.markdown import Markdown
|
||||
from ..topic.models import Topic
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from ...core.conf import settings
|
||||
|
||||
|
||||
class CommentLike(models.Model):
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ from __future__ import unicode_literals
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from django.db.models import F
|
||||
from django.utils import timezone
|
||||
|
||||
from ..core.conf import settings
|
||||
from .managers import CommentQuerySet
|
||||
|
||||
|
||||
|
|
|
@ -4,13 +4,16 @@ from __future__ import unicode_literals, division
|
|||
|
||||
from django.db import models, transaction
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from django.db.models import F
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...core.utils import get_query_string
|
||||
from .managers import CommentPollQuerySet, CommentPollChoiceQuerySet, CommentPollVoteQuerySet
|
||||
from .managers import (
|
||||
CommentPollQuerySet,
|
||||
CommentPollChoiceQuerySet,
|
||||
CommentPollVoteQuerySet)
|
||||
|
||||
|
||||
class PollMode(object):
|
||||
|
|
|
@ -4,8 +4,8 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.html import mark_safe
|
||||
from django.conf import settings
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core.tags.registry import register
|
||||
from .poll.utils.render import render_polls
|
||||
from .forms import CommentForm
|
||||
|
|
|
@ -12,11 +12,11 @@ from django.core.urlresolvers import reverse
|
|||
from django.template import Template, Context
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.six import BytesIO
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core.tests import utils
|
||||
from .models import Comment
|
||||
from .forms import CommentForm, CommentMoveForm, CommentImageForm
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url, include
|
||||
from django.conf import settings
|
||||
|
||||
from ..core.conf import settings
|
||||
import spirit.comment.bookmark.urls
|
||||
import spirit.comment.flag.urls
|
||||
import spirit.comment.history.urls
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.views.decorators.http import require_POST
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .settings import settings
|
||||
|
||||
__all__ = [
|
||||
'settings'
|
||||
]
|
|
@ -0,0 +1,102 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
These are the default settings. \
|
||||
They can be overridden by the project settings
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
|
||||
#: The category's PK containing all of the private topics.
|
||||
#: The category is auto-created and so this value should not change
|
||||
ST_TOPIC_PRIVATE_CATEGORY_PK = 1
|
||||
|
||||
#: Enable/disable the rate-limit for all forms
|
||||
ST_RATELIMIT_ENABLE = True
|
||||
#: The cache key prefix. This is mostly to avoid clashing with other apps
|
||||
ST_RATELIMIT_CACHE_PREFIX = 'srl'
|
||||
#: The cache ID for storing rate-limit related data.
|
||||
#: The cache ID must be a valid ``CACHES`` entry and
|
||||
#: the ``TIMEOUT`` must be ``None`` otherwise it will misbehave
|
||||
ST_RATELIMIT_CACHE = 'st_rate_limit'
|
||||
#: A warning will be printed when the ``TIMEOUT``
|
||||
#: is not ``None``. Setting this to ``True`` will silence it.
|
||||
#:
|
||||
#: .. Warning:: A ``ConfigurationError`` will be raised instead of a warning in Spirit > 0.5
|
||||
ST_RATELIMIT_SKIP_TIMEOUT_CHECK = False
|
||||
|
||||
#: Number of notifications per page
|
||||
ST_NOTIFICATIONS_PER_PAGE = 20
|
||||
|
||||
#: Maximum length for a comment
|
||||
ST_COMMENT_MAX_LEN = 3000
|
||||
#: Maximum number of mentions per comment willing to process
|
||||
ST_MENTIONS_PER_COMMENT = 30
|
||||
#: Minutes to wait before a given user
|
||||
#: will be able to post a duplicated comment/topic
|
||||
ST_DOUBLE_POST_THRESHOLD_MINUTES = 30
|
||||
|
||||
#: Number of next/previous pages the paginator will show
|
||||
ST_YT_PAGINATOR_PAGE_RANGE = 3
|
||||
|
||||
#: Minimum length for a given search query
|
||||
ST_SEARCH_QUERY_MIN_LEN = 3
|
||||
|
||||
#: Threshold in minutes before the user
|
||||
#: `"last seen"` info can be updated
|
||||
ST_USER_LAST_SEEN_THRESHOLD_MINUTES = 1
|
||||
|
||||
#: Settings this to ``True`` will require
|
||||
#: all users to be logged-in to access any section
|
||||
ST_PRIVATE_FORUM = False
|
||||
|
||||
#: Enable/disable image uploads within posts
|
||||
ST_UPLOAD_IMAGE_ENABLED = True
|
||||
#: Uploaded images will be validated against these formats.
|
||||
#: Also, the file choosing dialog will filter by these extensions.
|
||||
#: See the `Pillow docs <http://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html>`_
|
||||
#: for a list of supported formats
|
||||
#:
|
||||
#: .. Warning::
|
||||
#: Allowing PNG files is a security risk as it may contain malicious HTML.
|
||||
#: See `Django notes <https://docs.djangoproject.com/en/1.11/topics/security/#user-uploaded-content>`_
|
||||
ST_ALLOWED_UPLOAD_IMAGE_FORMAT = ('jpeg', 'jpg', 'gif')
|
||||
|
||||
#: Enable/disable file uploads within posts
|
||||
ST_UPLOAD_FILE_ENABLED = True
|
||||
#: Uploaded files will be validated against these formats.
|
||||
#: This is a map of extension and media-type. Both are used for validation.
|
||||
#:
|
||||
#: .. Note::
|
||||
#: To find a media-type just add an extension and an empty media-type,
|
||||
#: then try uploading a valid file for that extension and the expected
|
||||
#: media-type will be printed within the validation error.
|
||||
#: Either that or use the Linux ``file --mime-type ./my_file`` command
|
||||
ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE = {
|
||||
'doc': 'application/msword',
|
||||
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'pdf': 'application/pdf'}
|
||||
|
||||
#: Link protocols allowed within posts
|
||||
ST_ALLOWED_URL_PROTOCOLS = {
|
||||
'http', 'https', 'mailto', 'ftp', 'ftps',
|
||||
'git', 'svn', 'magnet', 'irc', 'ircs'}
|
||||
|
||||
#: Support unicode slugs. Set to ``False``
|
||||
#: to only allow ASCII chars
|
||||
ST_UNICODE_SLUGS = True
|
||||
|
||||
#: Reject duplicated emails when creating a new account
|
||||
ST_UNIQUE_EMAILS = True
|
||||
#: Make emails case insensitive
|
||||
ST_CASE_INSENSITIVE_EMAILS = True
|
||||
|
||||
# Tests helper
|
||||
ST_TESTS_RATELIMIT_NEVER_EXPIRE = False
|
||||
|
||||
# Full route to the spirit package
|
||||
ST_BASE_DIR = (
|
||||
os.path.dirname(
|
||||
os.path.dirname(
|
||||
os.path.dirname(__file__))))
|
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.conf import settings as django_settings
|
||||
|
||||
from . import defaults
|
||||
|
||||
__all__ = ['settings']
|
||||
|
||||
|
||||
class Settings:
|
||||
"""
|
||||
Get a setting from django settings or\
|
||||
Spirit's defaults. In that order
|
||||
"""
|
||||
|
||||
def __getattr__(self, item):
|
||||
try:
|
||||
return getattr(django_settings, item)
|
||||
except AttributeError:
|
||||
return getattr(defaults, item)
|
||||
|
||||
|
||||
settings = Settings()
|
|
@ -5,8 +5,8 @@ import os
|
|||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management import call_command
|
||||
from django.conf import settings
|
||||
|
||||
from ...conf import settings
|
||||
from ... import utils
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ from subprocess import call
|
|||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
|
||||
from ...conf import settings
|
||||
from ... import utils
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ from subprocess import call
|
|||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
|
||||
from ...conf import settings
|
||||
from ... import utils
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
from django.core.urlresolvers import resolve
|
||||
|
||||
|
@ -11,6 +10,8 @@ try:
|
|||
except ImportError: # Django < 1.10
|
||||
MiddlewareMixin = object
|
||||
|
||||
from .conf import settings
|
||||
|
||||
|
||||
class XForwardedForMiddleware(MiddlewareMixin):
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings as django_settings
|
||||
from ..conf import settings as st_settings
|
||||
|
||||
from .registry import register
|
||||
|
||||
|
@ -10,6 +10,6 @@ from .registry import register
|
|||
@register.simple_tag(takes_context=True)
|
||||
def load_settings(context, *settings):
|
||||
context['st_settings'] = {
|
||||
setting: getattr(django_settings, setting)
|
||||
setting: getattr(st_settings, setting)
|
||||
for setting in settings}
|
||||
return ''
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from .conf import settings
|
||||
|
||||
try:
|
||||
# TODO: remove this try block.
|
||||
|
|
|
@ -14,13 +14,13 @@ from django.utils import timezone
|
|||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.http import HttpResponse
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.contrib import messages
|
||||
from django.utils.timezone import utc
|
||||
from django.utils.http import urlunquote
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from ..conf import settings
|
||||
from ...category.models import Category
|
||||
from .. import utils
|
||||
from ..utils.forms import NestedModelChoiceField
|
||||
|
|
|
@ -6,13 +6,13 @@ import warnings
|
|||
from django.test import TestCase, RequestFactory, override_settings
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.contrib.messages.storage.fallback import FallbackStorage
|
||||
from django.conf import settings
|
||||
from django.core.cache import caches
|
||||
|
||||
from . import utils
|
||||
from ..utils.ratelimit import ratelimit as rl_module
|
||||
from ..utils.ratelimit import RateLimit
|
||||
from ..utils.ratelimit.decorators import ratelimit
|
||||
from ..conf import settings
|
||||
|
||||
|
||||
def setup_request_factory_messages(req):
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
from django.core.cache import caches, cache
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...topic.models import Topic
|
||||
from ...category.models import Category
|
||||
from ...comment.models import Comment
|
||||
|
|
|
@ -6,7 +6,8 @@ from functools import wraps
|
|||
from django.core.exceptions import PermissionDenied
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
from django.shortcuts import redirect
|
||||
from django.conf import settings
|
||||
|
||||
from ..conf import settings
|
||||
|
||||
|
||||
def moderator_required(view_func):
|
||||
|
|
|
@ -4,11 +4,11 @@ from __future__ import unicode_literals
|
|||
import re
|
||||
import copy
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
import mistune
|
||||
|
||||
from ...conf import settings
|
||||
from .utils.emoji import emojis
|
||||
|
||||
User = get_user_model()
|
||||
|
|
|
@ -4,9 +4,10 @@ from __future__ import unicode_literals
|
|||
|
||||
import mistune
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.html import escape
|
||||
|
||||
from ...conf import settings
|
||||
|
||||
|
||||
def sanitize_url(url):
|
||||
url = escape(url) # & -> & ...
|
||||
|
|
|
@ -4,9 +4,10 @@ from __future__ import unicode_literals
|
|||
import re
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.conf import settings
|
||||
from django.utils import translation
|
||||
|
||||
from ....conf import settings
|
||||
|
||||
|
||||
_PATTERN_POLL = re.compile(
|
||||
r'^(?:\[poll[^\]]*\])\n+'
|
||||
|
|
|
@ -7,7 +7,8 @@ from slugify import slugify as unicode_slugify
|
|||
from django.db.models.fields import SlugField
|
||||
from django.utils.encoding import smart_text
|
||||
from django.utils.text import slugify
|
||||
from django.conf import settings
|
||||
|
||||
from ..conf import settings
|
||||
|
||||
__all__ = ['AutoSlugField', ]
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.paginator import InvalidPage
|
||||
from django.conf import settings
|
||||
|
||||
from ...conf import settings
|
||||
|
||||
|
||||
class YTPaginator(object):
|
||||
|
|
|
@ -5,9 +5,9 @@ from __future__ import unicode_literals
|
|||
import hashlib
|
||||
import time
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import caches
|
||||
|
||||
from ...conf import settings
|
||||
from ..deprecations import warn
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, print_function
|
||||
|
||||
import os
|
||||
import functools
|
||||
import argparse
|
||||
from importlib import import_module
|
||||
from subprocess import call
|
||||
|
||||
|
||||
def create_project(project_name, path, exit_err):
|
||||
try:
|
||||
import_module(project_name)
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
exit_err(
|
||||
"'%s' conflicts with the name of an existing "
|
||||
"Python module and cannot be used as a project "
|
||||
"name" % project_name)
|
||||
|
||||
extra_path = os.path.dirname(os.path.dirname(__file__))
|
||||
template_path = os.path.join(extra_path, 'project_template')
|
||||
|
||||
command = [
|
||||
'django-admin',
|
||||
'startproject',
|
||||
'--template=' + template_path,
|
||||
project_name]
|
||||
|
||||
if path:
|
||||
command.append(path)
|
||||
|
||||
print('Creating spirit project...')
|
||||
|
||||
if call(command) != 0:
|
||||
exit_err(
|
||||
"Tried to run \"%s\" but it "
|
||||
"returned an error "
|
||||
"(should be printed above)\n" % ' '.join(command))
|
||||
|
||||
print('ok')
|
||||
|
||||
|
||||
def execute_from_command_line():
|
||||
parser = argparse.ArgumentParser(description='Spirit commands')
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
start_parser = subparsers.add_parser(
|
||||
'startproject', help='creates a Spirit project directory structure')
|
||||
start_parser.add_argument(
|
||||
'project_name', help='name of the project')
|
||||
start_parser.add_argument(
|
||||
'--path', default=None, help='optional destination directory')
|
||||
args = parser.parse_args()
|
||||
create_project(
|
||||
project_name=args.project_name,
|
||||
path=args.path,
|
||||
exit_err=functools.partial(parser.exit, 1))
|
||||
|
||||
|
||||
def main():
|
||||
execute_from_command_line()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
|
@ -4,7 +4,7 @@ import os
|
|||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.dev")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings.dev")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Django settings for {{ project_name }} project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django {{ django_version }}.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/{{ docs_version }}/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/{{ docs_version }}/howto/deployment/checklist/
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'spirit.core',
|
||||
'spirit.admin',
|
||||
'spirit.search',
|
||||
|
||||
'spirit.user',
|
||||
'spirit.user.admin',
|
||||
'spirit.user.auth',
|
||||
|
||||
'spirit.category',
|
||||
'spirit.category.admin',
|
||||
|
||||
'spirit.topic',
|
||||
'spirit.topic.admin',
|
||||
'spirit.topic.favorite',
|
||||
'spirit.topic.moderate',
|
||||
'spirit.topic.notification',
|
||||
'spirit.topic.poll', # todo: remove in Spirit v0.6
|
||||
'spirit.topic.private',
|
||||
'spirit.topic.unread',
|
||||
|
||||
'spirit.comment',
|
||||
'spirit.comment.bookmark',
|
||||
'spirit.comment.flag',
|
||||
'spirit.comment.flag.admin',
|
||||
'spirit.comment.history',
|
||||
'spirit.comment.like',
|
||||
'spirit.comment.poll',
|
||||
|
||||
'djconfig',
|
||||
'haystack',
|
||||
]
|
||||
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
# 'spirit.core.middleware.XForwardedForMiddleware',
|
||||
'spirit.user.middleware.TimezoneMiddleware',
|
||||
'spirit.user.middleware.LastIPMiddleware',
|
||||
'spirit.user.middleware.LastSeenMiddleware',
|
||||
'spirit.user.middleware.ActiveUserMiddleware',
|
||||
'spirit.core.middleware.PrivateForumMiddleware',
|
||||
'djconfig.middleware.DjConfigMiddleware',
|
||||
]
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'APP_DIRS': True,
|
||||
'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.template.context_processors.request',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'djconfig.context_processors.config',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
|
||||
'LOCATION': 'spirit_cache',
|
||||
},
|
||||
'st_rate_limit': {
|
||||
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
|
||||
'LOCATION': 'spirit_rl_cache',
|
||||
'TIMEOUT': None
|
||||
}
|
||||
}
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'spirit.user.auth.backends.UsernameAuthBackend',
|
||||
'spirit.user.auth.backends.EmailAuthBackend',
|
||||
]
|
||||
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
'default': {
|
||||
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
|
||||
'PATH': os.path.join(BASE_DIR, 'st_search'),
|
||||
},
|
||||
}
|
||||
|
||||
ROOT_URLCONF = '{{ project_name }}.urls'
|
||||
|
||||
WSGI_APPLICATION = '{{ project_name }}.wsgi.application'
|
||||
|
||||
LOGIN_URL = 'spirit:user:auth:login'
|
||||
LOGIN_REDIRECT_URL = 'spirit:user:update'
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
|
||||
# Send an email to the site admins
|
||||
# on error when DEBUG=False,
|
||||
# log to console on error always.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
'filters': ['require_debug_false'],
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
'file': {
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': os.path.join(BASE_DIR, 'django.log'),
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'': {
|
||||
'handlers': ['console', 'mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['console', 'mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
# Create your own dev_local.py
|
||||
# import * this module there and use it like this:
|
||||
# python manage.py runserver --settings=project.settings.dev_local
|
||||
# python manage.py runserver --settings={{ project_name }}.settings.dev_local
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
@ -15,7 +15,7 @@ from .base import *
|
|||
DEBUG = True
|
||||
|
||||
TEMPLATES[0]['OPTIONS']['debug'] = True
|
||||
# TEMPLATES[0]['OPTIONS']['string_if_invalid'] = '{{ %s }}' # Some Django templates relies on this being the default
|
||||
# TEMPLATES[0]['OPTIONS']['string_if_invalid'] = '\{\{%s\}\}' # Some Django templates relies on this being the default
|
||||
|
||||
ADMINS = (('John', 'john@example.com'), ) # Log email to console when DEBUG = False
|
||||
|
||||
|
@ -27,6 +27,9 @@ ALLOWED_HOSTS = ['127.0.0.1', ]
|
|||
# 'debug_toolbar',
|
||||
# ])
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
|
@ -4,23 +4,22 @@
|
|||
|
||||
# Create your own prod_local.py
|
||||
# import * this module there and use it like this:
|
||||
# python manage.py runserver --settings=project.settings.prod_local
|
||||
# python manage.py runserver --settings={{ project_name }}.settings.prod_local
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .base import *
|
||||
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#admins
|
||||
ADMINS = (('John', 'john@example.com'), )
|
||||
|
||||
# Secret key generator: https://djskgen.herokuapp.com/
|
||||
# You should set your key as an environ variable
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", "")
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", '{{ secret_key }}')
|
||||
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#allowed-hosts
|
||||
ALLOWED_HOSTS = ['.example.com', ]
|
||||
|
||||
# You can change this to something like 'MyForum <noreply@example.com>'
|
||||
|
@ -36,7 +35,9 @@ INSTALLED_APPS.extend([
|
|||
# 'my_app1',
|
||||
])
|
||||
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
|
@ -45,9 +46,6 @@ DATABASES = {
|
|||
'PASSWORD': 'mypassword',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '5432',
|
||||
# Django default is 0,
|
||||
# close after every request
|
||||
# 'CONN_MAX_AGE': 0, # todo: Spirit v0.5 change to Keep alive 60 secs, uncomment
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Django settings for running the tests of spirit app
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from .base import *
|
||||
|
||||
from spirit.settings import *
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
SECRET_KEY = 'TEST'
|
||||
|
|
@ -15,12 +15,12 @@ admin.site.login = login_required(admin.site.login)
|
|||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^', include(spirit.urls)),
|
||||
|
||||
# Examples:
|
||||
# url(r'^$', 'example.views.home', name='home'),
|
||||
# url(r'^example/', include('example.foo.urls')),
|
||||
|
||||
url(r'^', include(spirit.urls)),
|
||||
|
||||
# Uncomment the admin/doc line below to enable admin documentation:
|
||||
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings.dev")
|
||||
|
||||
application = get_wsgi_application()
|
|
@ -3,13 +3,13 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import smart_text
|
||||
|
||||
from haystack.forms import SearchForm
|
||||
from haystack.query import EmptySearchQuerySet
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..topic.models import Topic
|
||||
from ..category.models import Category
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
|
||||
from haystack import indexes
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..topic.models import Topic
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import datetime
|
|||
from django.test import TestCase, override_settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import Template, Context
|
||||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import timezone
|
||||
|
@ -14,6 +13,7 @@ from django.utils import timezone
|
|||
from haystack.query import SearchQuerySet
|
||||
from djconfig.utils import override_djconfig
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core.tests import utils
|
||||
from ..topic.models import Topic
|
||||
from .forms import BasicSearchForm, AdvancedSearchForm
|
||||
|
|
|
@ -7,6 +7,25 @@ from __future__ import unicode_literals
|
|||
import os
|
||||
from collections import OrderedDict
|
||||
|
||||
# TODO: Remove this whole module in Spirit 0.6
|
||||
|
||||
import warnings
|
||||
|
||||
class RemovedInNextVersionWarning2(DeprecationWarning):
|
||||
""""""
|
||||
|
||||
warnings.simplefilter("default", RemovedInNextVersionWarning2)
|
||||
|
||||
warnings.warn(
|
||||
"`spirit.settings` is deprecated and it will be removed in Spirit 0.6. "
|
||||
"You are most likely seeing this because settings.base.py contains "
|
||||
"`from spirit.settings import *`. "
|
||||
"The best way to procede is to create a clean project (run "
|
||||
"`spirit startproject mysite`) and modify the settings as needed. "
|
||||
"It's a straightforward procedure.",
|
||||
category=RemovedInNextVersionWarning2,
|
||||
stacklevel=2)
|
||||
|
||||
ST_TOPIC_PRIVATE_CATEGORY_PK = 1
|
||||
|
||||
ST_RATELIMIT_ENABLE = True
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from ...core.conf import settings
|
||||
|
||||
|
||||
class TopicFavorite(models.Model):
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ from __future__ import unicode_literals
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from django.db.models import F
|
||||
|
||||
from .managers import TopicQuerySet
|
||||
from ..core.utils.models import AutoSlugField
|
||||
from ..core.conf import settings
|
||||
|
||||
|
||||
class Topic(models.Model):
|
||||
|
|
|
@ -4,11 +4,11 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from django.db import IntegrityError, transaction
|
||||
|
||||
from .managers import TopicNotificationQuerySet
|
||||
from ...core.conf import settings
|
||||
|
||||
|
||||
UNDEFINED, MENTION, COMMENT = range(3)
|
||||
|
|
|
@ -7,12 +7,12 @@ from django.contrib.auth.decorators import login_required
|
|||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.utils.html import escape
|
||||
|
||||
from djconfig import config
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...core import utils
|
||||
from ...core.utils.paginator import yt_paginate
|
||||
from ...core.utils.paginator.infinite_paginator import paginate
|
||||
|
|
|
@ -5,9 +5,9 @@ from __future__ import unicode_literals
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import smart_bytes
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...core import utils
|
||||
from ...core.utils.widgets import MultipleInput
|
||||
from ...topic.models import Topic
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from .managers import TopicPrivateQuerySet
|
||||
from ...core.conf import settings
|
||||
|
||||
|
||||
class TopicPrivate(models.Model):
|
||||
|
|
|
@ -7,11 +7,11 @@ import hashlib
|
|||
from django.test import TestCase, override_settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import Template, Context
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from djconfig.utils import override_djconfig
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...core.tests import utils
|
||||
from ...category.models import Category
|
||||
from .models import TopicPrivate
|
||||
|
|
|
@ -9,10 +9,10 @@ from django.shortcuts import render, redirect, get_object_or_404
|
|||
from django.views.decorators.http import require_POST
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponsePermanentRedirect
|
||||
from django.conf import settings
|
||||
|
||||
from djconfig import config
|
||||
|
||||
from ...core.conf import settings
|
||||
from ...core import utils
|
||||
from ...core.utils.paginator import paginate, yt_paginate
|
||||
from ...core.utils.ratelimit.decorators import ratelimit
|
||||
|
|
|
@ -4,9 +4,10 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from ...core.conf import settings
|
||||
|
||||
|
||||
class TopicUnread(models.Model):
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ from __future__ import unicode_literals
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.http import HttpResponsePermanentRedirect
|
||||
from django.conf import settings
|
||||
|
||||
from djconfig import config
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
|
||||
from ...core.conf import settings
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ from django import forms
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from ...core.conf import settings
|
||||
from ..forms import CleanEmailMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
|
|
@ -7,8 +7,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.utils import timezone
|
||||
from django.template import defaultfilters
|
||||
from django.conf import settings
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core.utils.timezone import timezones
|
||||
from .models import UserProfile
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import logging
|
|||
|
||||
import pytz
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout
|
||||
from django.utils import timezone
|
||||
|
||||
|
@ -14,6 +13,7 @@ try:
|
|||
except ImportError: # Django < 1.10
|
||||
MiddlewareMixin = object
|
||||
|
||||
from ..core.conf import settings
|
||||
from .models import UserProfile
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def migrate_profiles(apps, schema_editor):
|
||||
from ...core.conf import settings
|
||||
|
||||
User = apps.get_model(settings.AUTH_USER_MODEL)
|
||||
UserProfile = apps.get_model('spirit_user', 'UserProfile')
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class User(AbstractUser):
|
|||
|
||||
|
||||
def user_model_checker(apps, schema_editor):
|
||||
from django.conf import settings
|
||||
from ...core.conf import settings
|
||||
|
||||
if not hasattr(settings, 'AUTH_USER_MODEL'):
|
||||
return
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.db import migrations
|
|||
|
||||
|
||||
def user_model_content_type(apps, schema_editor):
|
||||
from django.conf import settings
|
||||
from ...core.conf import settings
|
||||
|
||||
if not hasattr(settings, 'AUTH_USER_MODEL'):
|
||||
return
|
||||
|
|
|
@ -7,8 +7,8 @@ from django.db import models
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
||||
from ..core.conf import settings
|
||||
from ..core.utils.models import AutoSlugField
|
||||
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@ from django.contrib.sites.shortcuts import get_current_site
|
|||
from django.utils.translation import ugettext as _
|
||||
from django.template.loader import render_to_string
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
|
||||
from .tokens import UserActivationTokenGenerator, UserEmailChangeTokenGenerator
|
||||
from ...core.conf import settings
|
||||
from .tokens import (
|
||||
UserActivationTokenGenerator,
|
||||
UserEmailChangeTokenGenerator)
|
||||
|
||||
logger = logging.getLogger('django')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def sender(request, subject, template_name, context, to):
|
||||
|
|
Loading…
Reference in New Issue