mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 08:02:54 +11:00
Quote cleanup, fStrings and Deprecation fixes.
This commit is contained in:
parent
cd586f62fe
commit
e54790c8f9
17 changed files with 411 additions and 415 deletions
2
Pipfile
2
Pipfile
|
@ -10,5 +10,5 @@ docutils = "==0.15"
|
||||||
[scripts]
|
[scripts]
|
||||||
runserver = "sh -c \"./manage.py migrate && ./manage.py runserver 0:8000\""
|
runserver = "sh -c \"./manage.py migrate && ./manage.py runserver 0:8000\""
|
||||||
test = "pytest dpaste"
|
test = "pytest dpaste"
|
||||||
cleanup = "sh -c \"isort -rc dpaste && black --skip-string-normalization --line-length=80 --exclude='/(migrations)/' dpaste\""
|
cleanup = "sh -c \"isort -rc dpaste && black --line-length=80 --exclude='/(migrations)/' dpaste\""
|
||||||
docs = "sphinx-build docs docs/_build/html"
|
docs = "sphinx-build docs docs/_build/html"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
VERSION = (3, 4, 'a0')
|
VERSION = (3, 4, "a0")
|
||||||
|
|
||||||
__version__ = '{major}.{minor}{rest}'.format(
|
__version__ = "{major}.{minor}{rest}".format(
|
||||||
major=VERSION[0],
|
major=VERSION[0],
|
||||||
minor=VERSION[1],
|
minor=VERSION[1],
|
||||||
rest=''.join(str(i) for i in VERSION[2:]),
|
rest="".join(str(i) for i in VERSION[2:]),
|
||||||
)
|
)
|
||||||
|
|
||||||
default_app_config = 'dpaste.apps.dpasteAppConfig'
|
default_app_config = "dpaste.apps.dpasteAppConfig"
|
||||||
|
|
170
dpaste/apps.py
170
dpaste/apps.py
|
@ -1,14 +1,14 @@
|
||||||
from django.apps import AppConfig, apps
|
from django.apps import AppConfig, apps
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class dpasteAppConfig(AppConfig):
|
class dpasteAppConfig(AppConfig):
|
||||||
name = 'dpaste'
|
name = "dpaste"
|
||||||
verbose_name = 'dpaste'
|
verbose_name = "dpaste"
|
||||||
|
|
||||||
# The application title used throughout the user interface.
|
# The application title used throughout the user interface.
|
||||||
APPLICATION_NAME = 'dpaste'
|
APPLICATION_NAME = "dpaste"
|
||||||
|
|
||||||
# This content is loaded in the <head> section of each template.
|
# This content is loaded in the <head> section of each template.
|
||||||
# You can use it to add any HTML tags, specifically custom CSS styles.
|
# You can use it to add any HTML tags, specifically custom CSS styles.
|
||||||
|
@ -24,7 +24,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# .btn { background-color: blue; border: 3px solid yellow; }
|
# .btn { background-color: blue; border: 3px solid yellow; }
|
||||||
# </style>
|
# </style>
|
||||||
# """
|
# """
|
||||||
EXTRA_HEAD_HTML = ''
|
EXTRA_HEAD_HTML = ""
|
||||||
|
|
||||||
# Integer. Length of the random slug for each new snippet. In the rare
|
# Integer. Length of the random slug for each new snippet. In the rare
|
||||||
# case an existing slug is generated again, the length will increase by
|
# case an existing slug is generated again, the length will increase by
|
||||||
|
@ -35,12 +35,12 @@ class dpasteAppConfig(AppConfig):
|
||||||
# This is intentionally missing l and I as they look too similar with
|
# This is intentionally missing l and I as they look too similar with
|
||||||
# sans-serif fonts.
|
# sans-serif fonts.
|
||||||
SLUG_CHOICES = (
|
SLUG_CHOICES = (
|
||||||
'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890'
|
"abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
)
|
)
|
||||||
|
|
||||||
# String. The lexer key that is pre-selected in the dropdown. Note that
|
# String. The lexer key that is pre-selected in the dropdown. Note that
|
||||||
# this is only used if the user has not saved a snippet before, otherwise
|
# this is only used if the user has not saved a snippet before, otherwise
|
||||||
LEXER_DEFAULT = 'python'
|
LEXER_DEFAULT = "python"
|
||||||
|
|
||||||
# Integer. Maximum number of bytes per snippet.
|
# Integer. Maximum number of bytes per snippet.
|
||||||
MAX_CONTENT_LENGTH = 250 * 1024 * 1024
|
MAX_CONTENT_LENGTH = 250 * 1024 * 1024
|
||||||
|
@ -48,7 +48,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# A tuple of seconds and a descriptive string used in the lexer
|
# A tuple of seconds and a descriptive string used in the lexer
|
||||||
# expiration dropdown. Example::
|
# expiration dropdown. Example::
|
||||||
#
|
#
|
||||||
# from django.utils.translation import ugettext_lazy as _
|
# from django.utils.translation import gettext_lazy as _
|
||||||
# DPASTE_EXPIRE_CHOICES = (
|
# DPASTE_EXPIRE_CHOICES = (
|
||||||
# (3600, _('In one hour')),
|
# (3600, _('In one hour')),
|
||||||
# (3600 * 24 * 7, _('In one week')),
|
# (3600 * 24 * 7, _('In one week')),
|
||||||
|
@ -60,17 +60,17 @@ class dpasteAppConfig(AppConfig):
|
||||||
# you set the choice key to ``never``. The management command will ignore
|
# you set the choice key to ``never``. The management command will ignore
|
||||||
# these snippets::
|
# these snippets::
|
||||||
#
|
#
|
||||||
# from django.utils.translation import ugettext_lazy as _
|
# from django.utils.translation import gettext_lazy as _
|
||||||
# DPASTE_EXPIRE_CHOICES = (
|
# DPASTE_EXPIRE_CHOICES = (
|
||||||
# (3600, _('In one hour')),
|
# (3600, _('In one hour')),
|
||||||
# ('never', _('Never')),
|
# ('never', _('Never')),
|
||||||
# )
|
# )
|
||||||
EXPIRE_CHOICES = (
|
EXPIRE_CHOICES = (
|
||||||
('onetime', _('One-Time snippet')),
|
("onetime", _("One-Time snippet")),
|
||||||
(3600, _('In one hour')),
|
(3600, _("In one hour")),
|
||||||
(3600 * 24 * 7, _('In one week')),
|
(3600 * 24 * 7, _("In one week")),
|
||||||
(3600 * 24 * 30, _('In one month')),
|
(3600 * 24 * 30, _("In one month")),
|
||||||
('never', _('Never')),
|
("never", _("Never")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Default value for ``EXPIRE_CHOICES``
|
# Default value for ``EXPIRE_CHOICES``
|
||||||
|
@ -81,7 +81,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# enable one-time snippets you have to add a choice ``onetime`` to the
|
# enable one-time snippets you have to add a choice ``onetime`` to the
|
||||||
# expire choices::
|
# expire choices::
|
||||||
#
|
#
|
||||||
# from django.utils.translation import ugettext_lazy as _
|
# from django.utils.translation import gettext_lazy as _
|
||||||
# DPASTE_EXPIRE_CHOICES = (
|
# DPASTE_EXPIRE_CHOICES = (
|
||||||
# ('onetime', _('One-Time snippet')),
|
# ('onetime', _('One-Time snippet')),
|
||||||
# (3600, _('In one hour')),
|
# (3600, _('In one hour')),
|
||||||
|
@ -102,11 +102,11 @@ class dpasteAppConfig(AppConfig):
|
||||||
RAW_MODE_PLAIN_TEXT = True
|
RAW_MODE_PLAIN_TEXT = True
|
||||||
|
|
||||||
# Lexers which have wordwrap enabled by default
|
# Lexers which have wordwrap enabled by default
|
||||||
LEXER_WORDWRAP = ('rst',)
|
LEXER_WORDWRAP = ("rst",)
|
||||||
|
|
||||||
# Key names of the default text and code lexer.
|
# Key names of the default text and code lexer.
|
||||||
PLAIN_TEXT_SYMBOL = '_text'
|
PLAIN_TEXT_SYMBOL = "_text"
|
||||||
PLAIN_CODE_SYMBOL = '_code'
|
PLAIN_CODE_SYMBOL = "_code"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TEXT_FORMATTER(self):
|
def TEXT_FORMATTER(self):
|
||||||
|
@ -129,9 +129,9 @@ class dpasteAppConfig(AppConfig):
|
||||||
)
|
)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(self.PLAIN_TEXT_SYMBOL, 'Plain Text', PlainTextHighlighter),
|
(self.PLAIN_TEXT_SYMBOL, "Plain Text", PlainTextHighlighter),
|
||||||
('_markdown', 'Markdown', MarkdownHighlighter),
|
("_markdown", "Markdown", MarkdownHighlighter),
|
||||||
('_rst', 'reStructuredText', RestructuredTextHighlighter),
|
("_rst", "reStructuredText", RestructuredTextHighlighter),
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -159,7 +159,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
from jsx.lexer import JsxLexer
|
from jsx.lexer import JsxLexer
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(self.PLAIN_CODE_SYMBOL, 'Plain Code', PlainCodeHighlighter),
|
(self.PLAIN_CODE_SYMBOL, "Plain Code", PlainCodeHighlighter),
|
||||||
# ('abap', 'ABAP'),
|
# ('abap', 'ABAP'),
|
||||||
# ('abnf', 'ABNF'),
|
# ('abnf', 'ABNF'),
|
||||||
# ('ada', 'Ada'),
|
# ('ada', 'Ada'),
|
||||||
|
@ -180,8 +180,8 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('antlr-ruby', 'ANTLR With Ruby Target'),
|
# ('antlr-ruby', 'ANTLR With Ruby Target'),
|
||||||
# ('apacheconf', 'ApacheConf'),
|
# ('apacheconf', 'ApacheConf'),
|
||||||
# ('apl', 'APL'),
|
# ('apl', 'APL'),
|
||||||
('applescript', 'AppleScript'),
|
("applescript", "AppleScript"),
|
||||||
('arduino', 'Arduino'),
|
("arduino", "Arduino"),
|
||||||
# ('as', 'ActionScript'),
|
# ('as', 'ActionScript'),
|
||||||
# ('as3', 'ActionScript 3'),
|
# ('as3', 'ActionScript 3'),
|
||||||
# ('aspectj', 'AspectJ'),
|
# ('aspectj', 'AspectJ'),
|
||||||
|
@ -192,8 +192,8 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('autoit', 'AutoIt'),
|
# ('autoit', 'AutoIt'),
|
||||||
# ('awk', 'Awk'),
|
# ('awk', 'Awk'),
|
||||||
# ('basemake', 'Base Makefile'),
|
# ('basemake', 'Base Makefile'),
|
||||||
('bash', 'Bash'),
|
("bash", "Bash"),
|
||||||
('bat', 'Batchfile'),
|
("bat", "Batchfile"),
|
||||||
# ('bbcode', 'BBCode'),
|
# ('bbcode', 'BBCode'),
|
||||||
# ('bc', 'BC'),
|
# ('bc', 'BC'),
|
||||||
# ('befunge', 'Befunge'),
|
# ('befunge', 'Befunge'),
|
||||||
|
@ -207,7 +207,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('bro', 'Bro'),
|
# ('bro', 'Bro'),
|
||||||
# ('bst', 'BST'),
|
# ('bst', 'BST'),
|
||||||
# ('bugs', 'BUGS'),
|
# ('bugs', 'BUGS'),
|
||||||
('c', 'C'),
|
("c", "C"),
|
||||||
# ('c-objdump', 'c-objdump'),
|
# ('c-objdump', 'c-objdump'),
|
||||||
# ('ca65', 'ca65 assembler'),
|
# ('ca65', 'ca65 assembler'),
|
||||||
# ('cadl', 'cADL'),
|
# ('cadl', 'cADL'),
|
||||||
|
@ -226,15 +226,15 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('cirru', 'Cirru'),
|
# ('cirru', 'Cirru'),
|
||||||
# ('clay', 'Clay'),
|
# ('clay', 'Clay'),
|
||||||
# ('clean', 'Clean'),
|
# ('clean', 'Clean'),
|
||||||
('clojure', 'Clojure'),
|
("clojure", "Clojure"),
|
||||||
# ('clojurescript', 'ClojureScript'),
|
# ('clojurescript', 'ClojureScript'),
|
||||||
('cmake', 'CMake'),
|
("cmake", "CMake"),
|
||||||
# ('cobol', 'COBOL'),
|
# ('cobol', 'COBOL'),
|
||||||
# ('cobolfree', 'COBOLFree'),
|
# ('cobolfree', 'COBOLFree'),
|
||||||
('coffee-script', 'CoffeeScript'),
|
("coffee-script", "CoffeeScript"),
|
||||||
('common-lisp', 'Common Lisp'),
|
("common-lisp", "Common Lisp"),
|
||||||
# ('componentpascal', 'Component Pascal'),
|
# ('componentpascal', 'Component Pascal'),
|
||||||
('console', 'Console/Bash Session'),
|
("console", "Console/Bash Session"),
|
||||||
# ('control', 'Debian Control file'),
|
# ('control', 'Debian Control file'),
|
||||||
# ('coq', 'Coq'),
|
# ('coq', 'Coq'),
|
||||||
# ('cpp', 'C++'),
|
# ('cpp', 'C++'),
|
||||||
|
@ -244,11 +244,11 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('crmsh', 'Crmsh'),
|
# ('crmsh', 'Crmsh'),
|
||||||
# ('croc', 'Croc'),
|
# ('croc', 'Croc'),
|
||||||
# ('cryptol', 'Cryptol'),
|
# ('cryptol', 'Cryptol'),
|
||||||
('csharp', 'C#'),
|
("csharp", "C#"),
|
||||||
# ('csound', 'Csound Orchestra'),
|
# ('csound', 'Csound Orchestra'),
|
||||||
# ('csound-document', 'Csound Document'),
|
# ('csound-document', 'Csound Document'),
|
||||||
# ('csound-score', 'Csound Score'),
|
# ('csound-score', 'Csound Score'),
|
||||||
('css', 'CSS'),
|
("css", "CSS"),
|
||||||
# ('css+django', 'CSS+Django/Jinja'),
|
# ('css+django', 'CSS+Django/Jinja'),
|
||||||
# ('css+erb', 'CSS+Ruby'),
|
# ('css+erb', 'CSS+Ruby'),
|
||||||
# ('css+genshitext', 'CSS+Genshi Text'),
|
# ('css+genshitext', 'CSS+Genshi Text'),
|
||||||
|
@ -259,17 +259,17 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('css+php', 'CSS+PHP'),
|
# ('css+php', 'CSS+PHP'),
|
||||||
# ('css+smarty', 'CSS+Smarty'),
|
# ('css+smarty', 'CSS+Smarty'),
|
||||||
# ('cucumber', 'Gherkin'),
|
# ('cucumber', 'Gherkin'),
|
||||||
('cuda', 'CUDA'),
|
("cuda", "CUDA"),
|
||||||
# ('cypher', 'Cypher'),
|
# ('cypher', 'Cypher'),
|
||||||
# ('cython', 'Cython'),
|
# ('cython', 'Cython'),
|
||||||
# ('d', 'D'),
|
# ('d', 'D'),
|
||||||
# ('d-objdump', 'd-objdump'),
|
# ('d-objdump', 'd-objdump'),
|
||||||
('dart', 'Dart'),
|
("dart", "Dart"),
|
||||||
('delphi', 'Delphi'),
|
("delphi", "Delphi"),
|
||||||
# ('dg', 'dg'),
|
# ('dg', 'dg'),
|
||||||
('diff', 'Diff'),
|
("diff", "Diff"),
|
||||||
('django', 'Django/Jinja'),
|
("django", "Django/Jinja"),
|
||||||
('docker', 'Docker'),
|
("docker", "Docker"),
|
||||||
# ('doscon', 'MSDOS Session'),
|
# ('doscon', 'MSDOS Session'),
|
||||||
# ('dpatch', 'Darcs Patch'),
|
# ('dpatch', 'Darcs Patch'),
|
||||||
# ('dtd', 'DTD'),
|
# ('dtd', 'DTD'),
|
||||||
|
@ -283,12 +283,12 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('ec', 'eC'),
|
# ('ec', 'eC'),
|
||||||
# ('ecl', 'ECL'),
|
# ('ecl', 'ECL'),
|
||||||
# ('eiffel', 'Eiffel'),
|
# ('eiffel', 'Eiffel'),
|
||||||
('elixir', 'Elixir'),
|
("elixir", "Elixir"),
|
||||||
# ('elm', 'Elm'),
|
# ('elm', 'Elm'),
|
||||||
# ('emacs', 'EmacsLisp'),
|
# ('emacs', 'EmacsLisp'),
|
||||||
# ('erb', 'ERB'),
|
# ('erb', 'ERB'),
|
||||||
# ('erl', 'Erlang erl session'),
|
# ('erl', 'Erlang erl session'),
|
||||||
('erlang', 'Erlang'),
|
("erlang", "Erlang"),
|
||||||
# ('evoque', 'Evoque'),
|
# ('evoque', 'Evoque'),
|
||||||
# ('extempore', 'xtlang'),
|
# ('extempore', 'xtlang'),
|
||||||
# ('ezhil', 'Ezhil'),
|
# ('ezhil', 'Ezhil'),
|
||||||
|
@ -310,7 +310,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('genshitext', 'Genshi Text'),
|
# ('genshitext', 'Genshi Text'),
|
||||||
# ('glsl', 'GLSL'),
|
# ('glsl', 'GLSL'),
|
||||||
# ('gnuplot', 'Gnuplot'),
|
# ('gnuplot', 'Gnuplot'),
|
||||||
('go', 'Go'),
|
("go", "Go"),
|
||||||
# ('golo', 'Golo'),
|
# ('golo', 'Golo'),
|
||||||
# ('gooddata-cl', 'GoodData-CL'),
|
# ('gooddata-cl', 'GoodData-CL'),
|
||||||
# ('gosu', 'Gosu'),
|
# ('gosu', 'Gosu'),
|
||||||
|
@ -318,15 +318,15 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('groovy', 'Groovy'),
|
# ('groovy', 'Groovy'),
|
||||||
# ('gst', 'Gosu Template'),
|
# ('gst', 'Gosu Template'),
|
||||||
# ('haml', 'Haml'),
|
# ('haml', 'Haml'),
|
||||||
('handlebars', 'Handlebars'),
|
("handlebars", "Handlebars"),
|
||||||
('haskell', 'Haskell'),
|
("haskell", "Haskell"),
|
||||||
# ('haxeml', 'Hxml'),
|
# ('haxeml', 'Hxml'),
|
||||||
# ('hexdump', 'Hexdump'),
|
# ('hexdump', 'Hexdump'),
|
||||||
# ('hlsl', 'HLSL'),
|
# ('hlsl', 'HLSL'),
|
||||||
# ('hsail', 'HSAIL'),
|
# ('hsail', 'HSAIL'),
|
||||||
('html', 'HTML'),
|
("html", "HTML"),
|
||||||
# ('html+cheetah', 'HTML+Cheetah'),
|
# ('html+cheetah', 'HTML+Cheetah'),
|
||||||
('html+django', 'HTML + Django/Jinja'),
|
("html+django", "HTML + Django/Jinja"),
|
||||||
# ('html+evoque', 'HTML+Evoque'),
|
# ('html+evoque', 'HTML+Evoque'),
|
||||||
# ('html+genshi', 'HTML+Genshi'),
|
# ('html+genshi', 'HTML+Genshi'),
|
||||||
# ('html+handlebars', 'HTML+Handlebars'),
|
# ('html+handlebars', 'HTML+Handlebars'),
|
||||||
|
@ -349,22 +349,22 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('igor', 'Igor'),
|
# ('igor', 'Igor'),
|
||||||
# ('inform6', 'Inform 6'),
|
# ('inform6', 'Inform 6'),
|
||||||
# ('inform7', 'Inform 7'),
|
# ('inform7', 'Inform 7'),
|
||||||
('ini', 'INI'),
|
("ini", "INI"),
|
||||||
# ('io', 'Io'),
|
# ('io', 'Io'),
|
||||||
# ('ioke', 'Ioke'),
|
# ('ioke', 'Ioke'),
|
||||||
# ('ipython2', 'IPython'),
|
# ('ipython2', 'IPython'),
|
||||||
# ('ipython3', 'IPython3'),
|
# ('ipython3', 'IPython3'),
|
||||||
('ipythonconsole', 'IPython console session'),
|
("ipythonconsole", "IPython console session"),
|
||||||
('irc', 'IRC logs'),
|
("irc", "IRC logs"),
|
||||||
# ('isabelle', 'Isabelle'),
|
# ('isabelle', 'Isabelle'),
|
||||||
# ('j', 'J'),
|
# ('j', 'J'),
|
||||||
# ('jags', 'JAGS'),
|
# ('jags', 'JAGS'),
|
||||||
# ('jasmin', 'Jasmin'),
|
# ('jasmin', 'Jasmin'),
|
||||||
('java', 'Java'),
|
("java", "Java"),
|
||||||
# ('javascript+mozpreproc', 'Javascript+mozpreproc'),
|
# ('javascript+mozpreproc', 'Javascript+mozpreproc'),
|
||||||
# ('jcl', 'JCL'),
|
# ('jcl', 'JCL'),
|
||||||
# ('jlcon', 'Julia console'),
|
# ('jlcon', 'Julia console'),
|
||||||
('js', 'JavaScript'),
|
("js", "JavaScript"),
|
||||||
# ('js+cheetah', 'JavaScript+Cheetah'),
|
# ('js+cheetah', 'JavaScript+Cheetah'),
|
||||||
# ('js+django', 'JavaScript+Django/Jinja'),
|
# ('js+django', 'JavaScript+Django/Jinja'),
|
||||||
# ('js+erb', 'JavaScript+Ruby'),
|
# ('js+erb', 'JavaScript+Ruby'),
|
||||||
|
@ -375,8 +375,8 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('js+php', 'JavaScript+PHP'),
|
# ('js+php', 'JavaScript+PHP'),
|
||||||
# ('js+smarty', 'JavaScript+Smarty'),
|
# ('js+smarty', 'JavaScript+Smarty'),
|
||||||
# ('jsgf', 'JSGF'),
|
# ('jsgf', 'JSGF'),
|
||||||
('json', 'JSON'),
|
("json", "JSON"),
|
||||||
('jsx', 'JSX/React'),
|
("jsx", "JSX/React"),
|
||||||
# ('json-object', 'JSONBareObject'),
|
# ('json-object', 'JSONBareObject'),
|
||||||
# ('jsonld', 'JSON-LD'),
|
# ('jsonld', 'JSON-LD'),
|
||||||
# ('jsp', 'Java Server Page'),
|
# ('jsp', 'Java Server Page'),
|
||||||
|
@ -385,12 +385,12 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('kal', 'Kal'),
|
# ('kal', 'Kal'),
|
||||||
# ('kconfig', 'Kconfig'),
|
# ('kconfig', 'Kconfig'),
|
||||||
# ('koka', 'Koka'),
|
# ('koka', 'Koka'),
|
||||||
('kotlin', 'Kotlin'),
|
("kotlin", "Kotlin"),
|
||||||
# ('lagda', 'Literate Agda'),
|
# ('lagda', 'Literate Agda'),
|
||||||
# ('lasso', 'Lasso'),
|
# ('lasso', 'Lasso'),
|
||||||
# ('lcry', 'Literate Cryptol'),
|
# ('lcry', 'Literate Cryptol'),
|
||||||
# ('lean', 'Lean'),
|
# ('lean', 'Lean'),
|
||||||
('less', 'LessCSS'),
|
("less", "LessCSS"),
|
||||||
# ('lhs', 'Literate Haskell'),
|
# ('lhs', 'Literate Haskell'),
|
||||||
# ('lidr', 'Literate Idris'),
|
# ('lidr', 'Literate Idris'),
|
||||||
# ('lighty', 'Lighttpd configuration file'),
|
# ('lighty', 'Lighttpd configuration file'),
|
||||||
|
@ -401,14 +401,14 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('logos', 'Logos'),
|
# ('logos', 'Logos'),
|
||||||
# ('logtalk', 'Logtalk'),
|
# ('logtalk', 'Logtalk'),
|
||||||
# ('lsl', 'LSL'),
|
# ('lsl', 'LSL'),
|
||||||
('lua', 'Lua'),
|
("lua", "Lua"),
|
||||||
('make', 'Makefile'),
|
("make", "Makefile"),
|
||||||
# ('mako', 'Mako'),
|
# ('mako', 'Mako'),
|
||||||
# ('maql', 'MAQL'),
|
# ('maql', 'MAQL'),
|
||||||
# ('mask', 'Mask'),
|
# ('mask', 'Mask'),
|
||||||
# ('mason', 'Mason'),
|
# ('mason', 'Mason'),
|
||||||
# ('mathematica', 'Mathematica'),
|
# ('mathematica', 'Mathematica'),
|
||||||
('matlab', 'Matlab'),
|
("matlab", "Matlab"),
|
||||||
# ('matlabsession', 'Matlab session'),
|
# ('matlabsession', 'Matlab session'),
|
||||||
# ('md', 'markdown'),
|
# ('md', 'markdown'),
|
||||||
# ('minid', 'MiniD'),
|
# ('minid', 'MiniD'),
|
||||||
|
@ -433,16 +433,16 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('newlisp', 'NewLisp'),
|
# ('newlisp', 'NewLisp'),
|
||||||
# ('newspeak', 'Newspeak'),
|
# ('newspeak', 'Newspeak'),
|
||||||
# ('ng2', 'Angular2'),
|
# ('ng2', 'Angular2'),
|
||||||
('nginx', 'Nginx configuration file'),
|
("nginx", "Nginx configuration file"),
|
||||||
# ('nim', 'Nimrod'),
|
# ('nim', 'Nimrod'),
|
||||||
# ('nit', 'Nit'),
|
# ('nit', 'Nit'),
|
||||||
# ('nixos', 'Nix'),
|
# ('nixos', 'Nix'),
|
||||||
# ('nsis', 'NSIS'),
|
# ('nsis', 'NSIS'),
|
||||||
('numpy', 'NumPy'),
|
("numpy", "NumPy"),
|
||||||
# ('nusmv', 'NuSMV'),
|
# ('nusmv', 'NuSMV'),
|
||||||
# ('objdump', 'objdump'),
|
# ('objdump', 'objdump'),
|
||||||
# ('objdump-nasm', 'objdump-nasm'),
|
# ('objdump-nasm', 'objdump-nasm'),
|
||||||
('objective-c', 'Objective-C'),
|
("objective-c", "Objective-C"),
|
||||||
# ('objective-c++', 'Objective-C++'),
|
# ('objective-c++', 'Objective-C++'),
|
||||||
# ('objective-j', 'Objective-J'),
|
# ('objective-j', 'Objective-J'),
|
||||||
# ('ocaml', 'OCaml'),
|
# ('ocaml', 'OCaml'),
|
||||||
|
@ -455,14 +455,14 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('pan', 'Pan'),
|
# ('pan', 'Pan'),
|
||||||
# ('parasail', 'ParaSail'),
|
# ('parasail', 'ParaSail'),
|
||||||
# ('pawn', 'Pawn'),
|
# ('pawn', 'Pawn'),
|
||||||
('perl', 'Perl'),
|
("perl", "Perl"),
|
||||||
# ('perl6', 'Perl6'),
|
# ('perl6', 'Perl6'),
|
||||||
('php', 'PHP'),
|
("php", "PHP"),
|
||||||
# ('pig', 'Pig'),
|
# ('pig', 'Pig'),
|
||||||
# ('pike', 'Pike'),
|
# ('pike', 'Pike'),
|
||||||
# ('pkgconfig', 'PkgConfig'),
|
# ('pkgconfig', 'PkgConfig'),
|
||||||
# ('plpgsql', 'PL/pgSQL'),
|
# ('plpgsql', 'PL/pgSQL'),
|
||||||
('postgresql', 'PostgreSQL SQL dialect'),
|
("postgresql", "PostgreSQL SQL dialect"),
|
||||||
# ('postscript', 'PostScript'),
|
# ('postscript', 'PostScript'),
|
||||||
# ('pot', 'Gettext Catalog'),
|
# ('pot', 'Gettext Catalog'),
|
||||||
# ('pov', 'POVRay'),
|
# ('pov', 'POVRay'),
|
||||||
|
@ -479,7 +479,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('pycon', 'Python console session'),
|
# ('pycon', 'Python console session'),
|
||||||
# ('pypylog', 'PyPy Log'),
|
# ('pypylog', 'PyPy Log'),
|
||||||
# ('pytb', 'Python Traceback'),
|
# ('pytb', 'Python Traceback'),
|
||||||
('python', 'Python'),
|
("python", "Python"),
|
||||||
# ('python3', 'Python 3'),
|
# ('python3', 'Python 3'),
|
||||||
# ('qbasic', 'QBasic'),
|
# ('qbasic', 'QBasic'),
|
||||||
# ('qml', 'QML'),
|
# ('qml', 'QML'),
|
||||||
|
@ -494,7 +494,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('ragel-objc', 'Ragel in Objective C Host'),
|
# ('ragel-objc', 'Ragel in Objective C Host'),
|
||||||
# ('ragel-ruby', 'Ragel in Ruby Host'),
|
# ('ragel-ruby', 'Ragel in Ruby Host'),
|
||||||
# ('raw', 'Raw token data'),
|
# ('raw', 'Raw token data'),
|
||||||
('rb', 'Ruby'),
|
("rb", "Ruby"),
|
||||||
# ('rbcon', 'Ruby irb session'),
|
# ('rbcon', 'Ruby irb session'),
|
||||||
# ('rconsole', 'RConsole'),
|
# ('rconsole', 'RConsole'),
|
||||||
# ('rd', 'Rd'),
|
# ('rd', 'Rd'),
|
||||||
|
@ -511,17 +511,17 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('robotframework', 'RobotFramework'),
|
# ('robotframework', 'RobotFramework'),
|
||||||
# ('rql', 'RQL'),
|
# ('rql', 'RQL'),
|
||||||
# ('rsl', 'RSL'),
|
# ('rsl', 'RSL'),
|
||||||
('rst', 'reStructuredText'),
|
("rst", "reStructuredText"),
|
||||||
# ('rts', 'TrafficScript'),
|
# ('rts', 'TrafficScript'),
|
||||||
('rust', 'Rust'),
|
("rust", "Rust"),
|
||||||
# ('sas', 'SAS'),
|
# ('sas', 'SAS'),
|
||||||
('sass', 'Sass'),
|
("sass", "Sass"),
|
||||||
# ('sc', 'SuperCollider'),
|
# ('sc', 'SuperCollider'),
|
||||||
# ('scala', 'Scala'),
|
# ('scala', 'Scala'),
|
||||||
# ('scaml', 'Scaml'),
|
# ('scaml', 'Scaml'),
|
||||||
# ('scheme', 'Scheme'),
|
# ('scheme', 'Scheme'),
|
||||||
# ('scilab', 'Scilab'),
|
# ('scilab', 'Scilab'),
|
||||||
('scss', 'SCSS'),
|
("scss", "SCSS"),
|
||||||
# ('shen', 'Shen'),
|
# ('shen', 'Shen'),
|
||||||
# ('silver', 'Silver'),
|
# ('silver', 'Silver'),
|
||||||
# ('slim', 'Slim'),
|
# ('slim', 'Slim'),
|
||||||
|
@ -531,19 +531,19 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('sml', 'Standard ML'),
|
# ('sml', 'Standard ML'),
|
||||||
# ('snobol', 'Snobol'),
|
# ('snobol', 'Snobol'),
|
||||||
# ('snowball', 'Snowball'),
|
# ('snowball', 'Snowball'),
|
||||||
('sol', 'Solidity'),
|
("sol", "Solidity"),
|
||||||
# ('sourceslist', 'Debian Sourcelist'),
|
# ('sourceslist', 'Debian Sourcelist'),
|
||||||
# ('sp', 'SourcePawn'),
|
# ('sp', 'SourcePawn'),
|
||||||
# ('sparql', 'SPARQL'),
|
# ('sparql', 'SPARQL'),
|
||||||
# ('spec', 'RPMSpec'),
|
# ('spec', 'RPMSpec'),
|
||||||
# ('splus', 'S'),
|
# ('splus', 'S'),
|
||||||
('sql', 'SQL'),
|
("sql", "SQL"),
|
||||||
# ('sqlite3', 'sqlite3con'),
|
# ('sqlite3', 'sqlite3con'),
|
||||||
# ('squidconf', 'SquidConf'),
|
# ('squidconf', 'SquidConf'),
|
||||||
# ('ssp', 'Scalate Server Page'),
|
# ('ssp', 'Scalate Server Page'),
|
||||||
# ('stan', 'Stan'),
|
# ('stan', 'Stan'),
|
||||||
# ('stata', 'Stata'),
|
# ('stata', 'Stata'),
|
||||||
('swift', 'Swift'),
|
("swift", "Swift"),
|
||||||
# ('swig', 'SWIG'),
|
# ('swig', 'SWIG'),
|
||||||
# ('systemverilog', 'systemverilog'),
|
# ('systemverilog', 'systemverilog'),
|
||||||
# ('tads3', 'TADS 3'),
|
# ('tads3', 'TADS 3'),
|
||||||
|
@ -556,7 +556,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('termcap', 'Termcap'),
|
# ('termcap', 'Termcap'),
|
||||||
# ('terminfo', 'Terminfo'),
|
# ('terminfo', 'Terminfo'),
|
||||||
# ('terraform', 'Terraform'),
|
# ('terraform', 'Terraform'),
|
||||||
('tex', 'TeX'),
|
("tex", "TeX"),
|
||||||
# ('text', 'Text only'),
|
# ('text', 'Text only'),
|
||||||
# ('thrift', 'Thrift'),
|
# ('thrift', 'Thrift'),
|
||||||
# ('todotxt', 'Todotxt'),
|
# ('todotxt', 'Todotxt'),
|
||||||
|
@ -566,7 +566,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('tsql', 'Transact-SQL'),
|
# ('tsql', 'Transact-SQL'),
|
||||||
# ('turtle', 'Turtle'),
|
# ('turtle', 'Turtle'),
|
||||||
# ('twig', 'Twig'),
|
# ('twig', 'Twig'),
|
||||||
('typoscript', 'TypoScript'),
|
("typoscript", "TypoScript"),
|
||||||
# ('typoscriptcssdata', 'TypoScriptCssData'),
|
# ('typoscriptcssdata', 'TypoScriptCssData'),
|
||||||
# ('typoscripthtmldata', 'TypoScriptHtmlData'),
|
# ('typoscripthtmldata', 'TypoScriptHtmlData'),
|
||||||
# ('urbiscript', 'UrbiScript'),
|
# ('urbiscript', 'UrbiScript'),
|
||||||
|
@ -579,11 +579,11 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('verilog', 'verilog'),
|
# ('verilog', 'verilog'),
|
||||||
# ('vgl', 'VGL'),
|
# ('vgl', 'VGL'),
|
||||||
# ('vhdl', 'vhdl'),
|
# ('vhdl', 'vhdl'),
|
||||||
('vim', 'VimL'),
|
("vim", "VimL"),
|
||||||
# ('wdiff', 'WDiff'),
|
# ('wdiff', 'WDiff'),
|
||||||
# ('whiley', 'Whiley'),
|
# ('whiley', 'Whiley'),
|
||||||
# ('x10', 'X10'),
|
# ('x10', 'X10'),
|
||||||
('xml', 'XML'),
|
("xml", "XML"),
|
||||||
# ('xml+cheetah', 'XML+Cheetah'),
|
# ('xml+cheetah', 'XML+Cheetah'),
|
||||||
# ('xml+django', 'XML+Django/Jinja'),
|
# ('xml+django', 'XML+Django/Jinja'),
|
||||||
# ('xml+erb', 'XML+Ruby'),
|
# ('xml+erb', 'XML+Ruby'),
|
||||||
|
@ -596,10 +596,10 @@ class dpasteAppConfig(AppConfig):
|
||||||
# ('xml+velocity', 'XML+Velocity'),
|
# ('xml+velocity', 'XML+Velocity'),
|
||||||
# ('xorg.conf', 'Xorg'),
|
# ('xorg.conf', 'Xorg'),
|
||||||
# ('xquery', 'XQuery'),
|
# ('xquery', 'XQuery'),
|
||||||
('xslt', 'XSLT'),
|
("xslt", "XSLT"),
|
||||||
# ('xtend', 'Xtend'),
|
# ('xtend', 'Xtend'),
|
||||||
# ('xul+mozpreproc', 'XUL+mozpreproc'),
|
# ('xul+mozpreproc', 'XUL+mozpreproc'),
|
||||||
('yaml', 'YAML'),
|
("yaml", "YAML"),
|
||||||
# ('yaml+jinja', 'YAML+Jinja'),
|
# ('yaml+jinja', 'YAML+Jinja'),
|
||||||
# ('zephir', 'Zephir')
|
# ('zephir', 'Zephir')
|
||||||
]
|
]
|
||||||
|
@ -612,13 +612,13 @@ class dpasteAppConfig(AppConfig):
|
||||||
framework is installed, it uses the current Site domain. Otherwise
|
framework is installed, it uses the current Site domain. Otherwise
|
||||||
it falls back to 'https://dpaste.de'
|
it falls back to 'https://dpaste.de'
|
||||||
"""
|
"""
|
||||||
if apps.is_installed('django.contrib.sites'):
|
if apps.is_installed("django.contrib.sites"):
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
|
|
||||||
site = get_current_site(request)
|
site = get_current_site(request)
|
||||||
if site:
|
if site:
|
||||||
return 'https://{0}'.format(site.domain)
|
return f"https://{site.domain}"
|
||||||
return 'https://dpaste.de'
|
return "https://dpaste.de"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_template_context(self):
|
def extra_template_context(self):
|
||||||
|
@ -627,6 +627,6 @@ class dpasteAppConfig(AppConfig):
|
||||||
all Template Views.
|
all Template Views.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'dpaste_application_name': self.APPLICATION_NAME,
|
"dpaste_application_name": self.APPLICATION_NAME,
|
||||||
'dpaste_extra_head_html': mark_safe(self.EXTRA_HEAD_HTML),
|
"dpaste_extra_head_html": mark_safe(self.EXTRA_HEAD_HTML),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,19 @@ import datetime
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .highlight import LEXER_CHOICES, LEXER_DEFAULT, LEXER_KEYS
|
from .highlight import LEXER_CHOICES, LEXER_DEFAULT, LEXER_KEYS
|
||||||
from .models import Snippet
|
from .models import Snippet
|
||||||
|
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
|
|
||||||
|
|
||||||
def get_expire_values(expires):
|
def get_expire_values(expires):
|
||||||
if expires == 'never':
|
if expires == "never":
|
||||||
expire_type = Snippet.EXPIRE_KEEP
|
expire_type = Snippet.EXPIRE_KEEP
|
||||||
expires = None
|
expires = None
|
||||||
elif expires == 'onetime':
|
elif expires == "onetime":
|
||||||
expire_type = Snippet.EXPIRE_ONETIME
|
expire_type = Snippet.EXPIRE_ONETIME
|
||||||
expires = None
|
expires = None
|
||||||
else:
|
else:
|
||||||
|
@ -28,63 +28,63 @@ def get_expire_values(expires):
|
||||||
|
|
||||||
class SnippetForm(forms.ModelForm):
|
class SnippetForm(forms.ModelForm):
|
||||||
content = forms.CharField(
|
content = forms.CharField(
|
||||||
label=_('Content'),
|
label=_("Content"),
|
||||||
widget=forms.Textarea(
|
widget=forms.Textarea(
|
||||||
attrs={'placeholder': _('Awesome code goes here...')}
|
attrs={"placeholder": _("Awesome code goes here...")}
|
||||||
),
|
),
|
||||||
max_length=config.MAX_CONTENT_LENGTH,
|
max_length=config.MAX_CONTENT_LENGTH,
|
||||||
strip=False,
|
strip=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
lexer = forms.ChoiceField(
|
lexer = forms.ChoiceField(
|
||||||
label=_('Lexer'), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
|
label=_("Lexer"), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
|
||||||
)
|
)
|
||||||
|
|
||||||
expires = forms.ChoiceField(
|
expires = forms.ChoiceField(
|
||||||
label=_('Expires'),
|
label=_("Expires"),
|
||||||
choices=config.EXPIRE_CHOICES,
|
choices=config.EXPIRE_CHOICES,
|
||||||
initial=config.EXPIRE_DEFAULT,
|
initial=config.EXPIRE_DEFAULT,
|
||||||
)
|
)
|
||||||
|
|
||||||
rtl = forms.BooleanField(label=_('Right to Left'), required=False)
|
rtl = forms.BooleanField(label=_("Right to Left"), required=False)
|
||||||
|
|
||||||
# Honeypot field
|
# Honeypot field
|
||||||
title = forms.CharField(
|
title = forms.CharField(
|
||||||
label=_('Title'),
|
label=_("Title"),
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.TextInput(attrs={'autocomplete': 'off'}),
|
widget=forms.TextInput(attrs={"autocomplete": "off"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Snippet
|
model = Snippet
|
||||||
fields = ('content', 'lexer', 'rtl')
|
fields = ("content", "lexer", "rtl")
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(SnippetForm, self).__init__(*args, **kwargs)
|
super(SnippetForm, self).__init__(*args, **kwargs)
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
# Set the recently used lexer if we have any
|
# Set the recently used lexer if we have any
|
||||||
session_lexer = self.request.session.get('lexer')
|
session_lexer = self.request.session.get("lexer")
|
||||||
if session_lexer and session_lexer in LEXER_KEYS:
|
if session_lexer and session_lexer in LEXER_KEYS:
|
||||||
self.fields['lexer'].initial = session_lexer
|
self.fields["lexer"].initial = session_lexer
|
||||||
|
|
||||||
# if the lexer is given via GET, set it
|
# if the lexer is given via GET, set it
|
||||||
if 'l' in request.GET and request.GET['l'] in LEXER_KEYS:
|
if "l" in request.GET and request.GET["l"] in LEXER_KEYS:
|
||||||
self.fields['lexer'].initial = request.GET['l']
|
self.fields["lexer"].initial = request.GET["l"]
|
||||||
|
|
||||||
def clean_content(self):
|
def clean_content(self):
|
||||||
content = self.cleaned_data.get('content', '')
|
content = self.cleaned_data.get("content", "")
|
||||||
if not content.strip():
|
if not content.strip():
|
||||||
raise forms.ValidationError(_('This field is required.'))
|
raise forms.ValidationError(_("This field is required."))
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def clean_expires(self):
|
def clean_expires(self):
|
||||||
"""
|
"""
|
||||||
Extract the 'expire_type' from the choice of expire choices.
|
Extract the 'expire_type' from the choice of expire choices.
|
||||||
"""
|
"""
|
||||||
expires = self.cleaned_data['expires']
|
expires = self.cleaned_data["expires"]
|
||||||
expires, expire_type = get_expire_values(expires)
|
expires, expire_type = get_expire_values(expires)
|
||||||
self.cleaned_data['expire_type'] = expire_type
|
self.cleaned_data["expire_type"] = expire_type
|
||||||
return expires
|
return expires
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
@ -92,8 +92,8 @@ class SnippetForm(forms.ModelForm):
|
||||||
The `title` field is a hidden honeypot field. If its filled,
|
The `title` field is a hidden honeypot field. If its filled,
|
||||||
this is likely spam.
|
this is likely spam.
|
||||||
"""
|
"""
|
||||||
if self.cleaned_data.get('title'):
|
if self.cleaned_data.get("title"):
|
||||||
raise forms.ValidationError('This snippet was identified as Spam.')
|
raise forms.ValidationError("This snippet was identified as Spam.")
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
def save(self, parent=None, *args, **kwargs):
|
def save(self, parent=None, *args, **kwargs):
|
||||||
|
@ -102,17 +102,17 @@ class SnippetForm(forms.ModelForm):
|
||||||
|
|
||||||
# Add expire timestamp. None indicates 'keep forever', use the default
|
# Add expire timestamp. None indicates 'keep forever', use the default
|
||||||
# null state of the db column for that.
|
# null state of the db column for that.
|
||||||
self.instance.expires = self.cleaned_data['expires']
|
self.instance.expires = self.cleaned_data["expires"]
|
||||||
self.instance.expire_type = self.cleaned_data['expire_type']
|
self.instance.expire_type = self.cleaned_data["expire_type"]
|
||||||
|
|
||||||
# Save snippet in the db
|
# Save snippet in the db
|
||||||
super(SnippetForm, self).save(*args, **kwargs)
|
super(SnippetForm, self).save(*args, **kwargs)
|
||||||
|
|
||||||
# Add the snippet to the user session list
|
# Add the snippet to the user session list
|
||||||
self.request.session.setdefault('snippet_list', [])
|
self.request.session.setdefault("snippet_list", [])
|
||||||
self.request.session['snippet_list'] += [self.instance.pk]
|
self.request.session["snippet_list"] += [self.instance.pk]
|
||||||
|
|
||||||
# Save the lexer in the session so we can use it later again
|
# Save the lexer in the session so we can use it later again
|
||||||
self.request.session['lexer'] = self.cleaned_data['lexer']
|
self.request.session["lexer"] = self.cleaned_data["lexer"]
|
||||||
|
|
||||||
return self.instance
|
return self.instance
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.apps import apps
|
||||||
from django.template.defaultfilters import escape, linebreaksbr
|
from django.template.defaultfilters import escape, linebreaksbr
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from pygments import highlight
|
from pygments import highlight
|
||||||
from pygments.formatters.html import HtmlFormatter
|
from pygments.formatters.html import HtmlFormatter
|
||||||
from pygments.lexers import get_lexer_by_name
|
from pygments.lexers import get_lexer_by_name
|
||||||
|
@ -12,7 +12,7 @@ from pygments.lexers.python import PythonLexer
|
||||||
from pygments.util import ClassNotFound
|
from pygments.util import ClassNotFound
|
||||||
|
|
||||||
logger = getLogger(__file__)
|
logger = getLogger(__file__)
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
@ -21,14 +21,14 @@ config = apps.get_app_config('dpaste')
|
||||||
|
|
||||||
|
|
||||||
class Highlighter(object):
|
class Highlighter(object):
|
||||||
template_name = 'dpaste/highlight/code.html'
|
template_name = "dpaste/highlight/code.html"
|
||||||
|
|
||||||
def highlight(self, code_string, lexer_name=None):
|
def highlight(self, code_string, lexer_name=None):
|
||||||
"""Subclasses need to override this."""
|
"""Subclasses need to override this."""
|
||||||
return code_string
|
return code_string
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_lexer_display_name(lexer_name, fallback=_('(Deprecated Lexer)')):
|
def get_lexer_display_name(lexer_name, fallback=_("(Deprecated Lexer)")):
|
||||||
for l in config.TEXT_FORMATTER + config.CODE_FORMATTER:
|
for l in config.TEXT_FORMATTER + config.CODE_FORMATTER:
|
||||||
if l[0] == lexer_name:
|
if l[0] == lexer_name:
|
||||||
return l[1]
|
return l[1]
|
||||||
|
@ -37,11 +37,11 @@ class Highlighter(object):
|
||||||
def render(self, code_string, lexer_name, direction=None, **kwargs):
|
def render(self, code_string, lexer_name, direction=None, **kwargs):
|
||||||
highlighted_string = self.highlight(code_string, lexer_name=lexer_name)
|
highlighted_string = self.highlight(code_string, lexer_name=lexer_name)
|
||||||
context = {
|
context = {
|
||||||
'highlighted': highlighted_string,
|
"highlighted": highlighted_string,
|
||||||
'highlighted_splitted': highlighted_string.splitlines(),
|
"highlighted_splitted": highlighted_string.splitlines(),
|
||||||
'lexer_name': lexer_name,
|
"lexer_name": lexer_name,
|
||||||
'lexer_display_name': self.get_lexer_display_name(lexer_name),
|
"lexer_display_name": self.get_lexer_display_name(lexer_name),
|
||||||
'direction': direction,
|
"direction": direction,
|
||||||
}
|
}
|
||||||
context.update(kwargs)
|
context.update(kwargs)
|
||||||
return render_to_string(self.template_name, context)
|
return render_to_string(self.template_name, context)
|
||||||
|
@ -50,7 +50,7 @@ class Highlighter(object):
|
||||||
class PlainTextHighlighter(Highlighter):
|
class PlainTextHighlighter(Highlighter):
|
||||||
"""Plain Text. Just replace linebreaks."""
|
"""Plain Text. Just replace linebreaks."""
|
||||||
|
|
||||||
template_name = 'dpaste/highlight/text.html'
|
template_name = "dpaste/highlight/text.html"
|
||||||
|
|
||||||
def highlight(self, code_string, **kwargs):
|
def highlight(self, code_string, **kwargs):
|
||||||
return linebreaksbr(code_string)
|
return linebreaksbr(code_string)
|
||||||
|
@ -60,17 +60,17 @@ class MarkdownHighlighter(PlainTextHighlighter):
|
||||||
"""Markdown"""
|
"""Markdown"""
|
||||||
|
|
||||||
extensions = (
|
extensions = (
|
||||||
'tables',
|
"tables",
|
||||||
'fenced-code',
|
"fenced-code",
|
||||||
'footnotes',
|
"footnotes",
|
||||||
'autolink,',
|
"autolink,",
|
||||||
'strikethrough',
|
"strikethrough",
|
||||||
'underline',
|
"underline",
|
||||||
'quote',
|
"quote",
|
||||||
'superscript',
|
"superscript",
|
||||||
'math',
|
"math",
|
||||||
)
|
)
|
||||||
render_flags = ('skip-html',)
|
render_flags = ("skip-html",)
|
||||||
|
|
||||||
def highlight(self, code_string, **kwargs):
|
def highlight(self, code_string, **kwargs):
|
||||||
import misaka
|
import misaka
|
||||||
|
@ -87,22 +87,22 @@ class MarkdownHighlighter(PlainTextHighlighter):
|
||||||
class RestructuredTextHighlighter(PlainTextHighlighter):
|
class RestructuredTextHighlighter(PlainTextHighlighter):
|
||||||
"""Restructured Text"""
|
"""Restructured Text"""
|
||||||
|
|
||||||
rst_part_name = 'html_body'
|
rst_part_name = "html_body"
|
||||||
publish_args = {
|
publish_args = {
|
||||||
'writer_name': 'html5_polyglot',
|
"writer_name": "html5_polyglot",
|
||||||
'settings_overrides': {
|
"settings_overrides": {
|
||||||
'raw_enabled': False,
|
"raw_enabled": False,
|
||||||
'file_insertion_enabled': False,
|
"file_insertion_enabled": False,
|
||||||
'halt_level': 5,
|
"halt_level": 5,
|
||||||
'report_level': 2,
|
"report_level": 2,
|
||||||
'warning_stream': '/dev/null',
|
"warning_stream": "/dev/null",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def highlight(self, code_string, **kwargs):
|
def highlight(self, code_string, **kwargs):
|
||||||
from docutils.core import publish_parts
|
from docutils.core import publish_parts
|
||||||
|
|
||||||
self.publish_args['source'] = code_string
|
self.publish_args["source"] = code_string
|
||||||
parts = publish_parts(**self.publish_args)
|
parts = publish_parts(**self.publish_args)
|
||||||
return mark_safe(parts[self.rst_part_name])
|
return mark_safe(parts[self.rst_part_name])
|
||||||
|
|
||||||
|
@ -126,9 +126,9 @@ class PlainCodeHighlighter(Highlighter):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def highlight(self, code_string, **kwargs):
|
def highlight(self, code_string, **kwargs):
|
||||||
return '\n'.join(
|
return "\n".join(
|
||||||
[
|
[
|
||||||
'<span class="plain">{}</span>'.format(escape(l) or '​')
|
'<span class="plain">{}</span>'.format(escape(l) or "​")
|
||||||
for l in code_string.splitlines()
|
for l in code_string.splitlines()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -149,7 +149,7 @@ class PygmentsHighlighter(Highlighter):
|
||||||
try:
|
try:
|
||||||
self.lexer = get_lexer_by_name(lexer_name)
|
self.lexer = get_lexer_by_name(lexer_name)
|
||||||
except ClassNotFound:
|
except ClassNotFound:
|
||||||
logger.warning('Lexer for given name %s not found', lexer_name)
|
logger.warning("Lexer for given name %s not found", lexer_name)
|
||||||
self.lexer = self.lexer_fallback
|
self.lexer = self.lexer_fallback
|
||||||
|
|
||||||
return highlight(code_string, self.lexer, self.formatter)
|
return highlight(code_string, self.lexer, self.formatter)
|
||||||
|
@ -190,8 +190,8 @@ def get_highlighter_class(lexer_name):
|
||||||
|
|
||||||
# Generate a list of Form choices of all lexer.
|
# Generate a list of Form choices of all lexer.
|
||||||
LEXER_CHOICES = (
|
LEXER_CHOICES = (
|
||||||
(_('Text'), [i[:2] for i in config.TEXT_FORMATTER]),
|
(_("Text"), [i[:2] for i in config.TEXT_FORMATTER]),
|
||||||
(_('Code'), [i[:2] for i in config.CODE_FORMATTER]),
|
(_("Code"), [i[:2] for i in config.CODE_FORMATTER]),
|
||||||
)
|
)
|
||||||
|
|
||||||
# List of all Lexer Keys
|
# List of all Lexer Keys
|
||||||
|
|
|
@ -9,10 +9,10 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--dry-run',
|
"--dry-run",
|
||||||
action='store_true',
|
action="store_true",
|
||||||
dest='dry_run',
|
dest="dry_run",
|
||||||
help='Don\'t do anything.',
|
help="Don't do anything.",
|
||||||
),
|
),
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
@ -29,7 +29,7 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
for d in deleteable_snippets:
|
for d in deleteable_snippets:
|
||||||
self.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires))
|
self.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires))
|
||||||
if options.get('dry_run'):
|
if options.get("dry_run"):
|
||||||
self.stdout.write('Dry run - Not actually deleting snippets!\n')
|
self.stdout.write("Dry run - Not actually deleting snippets!\n")
|
||||||
else:
|
else:
|
||||||
deleteable_snippets.delete()
|
deleteable_snippets.delete()
|
||||||
|
|
|
@ -4,12 +4,12 @@ from random import SystemRandom
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from six import python_2_unicode_compatible
|
from six import python_2_unicode_compatible
|
||||||
|
|
||||||
from dpaste import highlight
|
from dpaste import highlight
|
||||||
|
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
logger = getLogger(__file__)
|
logger = getLogger(__file__)
|
||||||
R = SystemRandom()
|
R = SystemRandom()
|
||||||
|
|
||||||
|
@ -17,11 +17,11 @@ R = SystemRandom()
|
||||||
def generate_secret_id(length):
|
def generate_secret_id(length):
|
||||||
if length > config.SLUG_LENGTH:
|
if length > config.SLUG_LENGTH:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
'Slug creation triggered a duplicate, '
|
"Slug creation triggered a duplicate, "
|
||||||
'consider increasing the SLUG_LENGTH.'
|
"consider increasing the SLUG_LENGTH."
|
||||||
)
|
)
|
||||||
|
|
||||||
secret_id = ''.join(
|
secret_id = "".join(
|
||||||
[
|
[
|
||||||
R.choice(config.SLUG_CHOICES)
|
R.choice(config.SLUG_CHOICES)
|
||||||
for i in range(length or config.SLUG_LENGTH)
|
for i in range(length or config.SLUG_LENGTH)
|
||||||
|
@ -45,37 +45,37 @@ class Snippet(models.Model):
|
||||||
EXPIRE_KEEP = 2
|
EXPIRE_KEEP = 2
|
||||||
EXPIRE_ONETIME = 3
|
EXPIRE_ONETIME = 3
|
||||||
EXPIRE_CHOICES = (
|
EXPIRE_CHOICES = (
|
||||||
(EXPIRE_TIME, _('Expire by timestamp')),
|
(EXPIRE_TIME, _("Expire by timestamp")),
|
||||||
(EXPIRE_KEEP, _('Keep Forever')),
|
(EXPIRE_KEEP, _("Keep Forever")),
|
||||||
(EXPIRE_ONETIME, _('One-Time snippet')),
|
(EXPIRE_ONETIME, _("One-Time snippet")),
|
||||||
)
|
)
|
||||||
|
|
||||||
secret_id = models.CharField(
|
secret_id = models.CharField(
|
||||||
_('Secret ID'), max_length=255, blank=True, null=True, unique=True
|
_("Secret ID"), max_length=255, blank=True, null=True, unique=True
|
||||||
)
|
)
|
||||||
content = models.TextField(_('Content'))
|
content = models.TextField(_("Content"))
|
||||||
lexer = models.CharField(
|
lexer = models.CharField(
|
||||||
_('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT
|
_("Lexer"), max_length=30, default=highlight.LEXER_DEFAULT
|
||||||
)
|
)
|
||||||
published = models.DateTimeField(_('Published'), auto_now_add=True)
|
published = models.DateTimeField(_("Published"), auto_now_add=True)
|
||||||
expire_type = models.PositiveSmallIntegerField(
|
expire_type = models.PositiveSmallIntegerField(
|
||||||
_('Expire Type'), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][0]
|
_("Expire Type"), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][0]
|
||||||
)
|
)
|
||||||
expires = models.DateTimeField(_('Expires'), blank=True, null=True)
|
expires = models.DateTimeField(_("Expires"), blank=True, null=True)
|
||||||
view_count = models.PositiveIntegerField(_('View count'), default=0)
|
view_count = models.PositiveIntegerField(_("View count"), default=0)
|
||||||
rtl = models.BooleanField(_('Right-to-left'), default=False)
|
rtl = models.BooleanField(_("Right-to-left"), default=False)
|
||||||
parent = models.ForeignKey(
|
parent = models.ForeignKey(
|
||||||
'self',
|
"self",
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name=_('Parent Snippet'),
|
verbose_name=_("Parent Snippet"),
|
||||||
related_name='children',
|
related_name="children",
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('-published',)
|
ordering = ("-published",)
|
||||||
db_table = 'dpaste_snippet'
|
db_table = "dpaste_snippet"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.secret_id
|
return self.secret_id
|
||||||
|
@ -86,14 +86,14 @@ class Snippet(models.Model):
|
||||||
super(Snippet, self).save(*args, **kwargs)
|
super(Snippet, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('snippet_details', kwargs={'snippet_id': self.secret_id})
|
return reverse("snippet_details", kwargs={"snippet_id": self.secret_id})
|
||||||
|
|
||||||
def highlight(self):
|
def highlight(self):
|
||||||
HighlighterClass = highlight.get_highlighter_class(self.lexer)
|
HighlighterClass = highlight.get_highlighter_class(self.lexer)
|
||||||
return HighlighterClass().render(
|
return HighlighterClass().render(
|
||||||
code_string=self.content,
|
code_string=self.content,
|
||||||
lexer_name=self.lexer,
|
lexer_name=self.lexer,
|
||||||
direction='rtl' if self.rtl else 'ltr',
|
direction="rtl" if self.rtl else "ltr",
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -14,17 +14,17 @@ PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split(
|
||||||
)
|
)
|
||||||
|
|
||||||
PYTHON_BIN = os.path.dirname(sys.executable)
|
PYTHON_BIN = os.path.dirname(sys.executable)
|
||||||
if os.path.exists(os.path.join(PYTHON_BIN, 'activate_this.py')):
|
if os.path.exists(os.path.join(PYTHON_BIN, "activate_this.py")):
|
||||||
# Assume that the presence of 'activate_this.py' in the python bin/
|
# Assume that the presence of 'activate_this.py' in the python bin/
|
||||||
# directory means that we're running in a virtual environment. Set the
|
# directory means that we're running in a virtual environment. Set the
|
||||||
# variable root to $VIRTUALENV/var.
|
# variable root to $VIRTUALENV/var.
|
||||||
VAR_ROOT = os.path.join(os.path.dirname(PYTHON_BIN), 'var')
|
VAR_ROOT = os.path.join(os.path.dirname(PYTHON_BIN), "var")
|
||||||
if not os.path.exists(VAR_ROOT):
|
if not os.path.exists(VAR_ROOT):
|
||||||
os.mkdir(VAR_ROOT)
|
os.mkdir(VAR_ROOT)
|
||||||
else:
|
else:
|
||||||
# Set the variable root to the local configuration location (which is
|
# Set the variable root to the local configuration location (which is
|
||||||
# ignored by the repository).
|
# ignored by the repository).
|
||||||
VAR_ROOT = os.path.join(PROJECT_DIR, PROJECT_MODULE_NAME, 'conf', 'local')
|
VAR_ROOT = os.path.join(PROJECT_DIR, PROJECT_MODULE_NAME, "conf", "local")
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Generic Django project settings
|
# Generic Django project settings
|
||||||
|
@ -34,13 +34,13 @@ DEBUG = False
|
||||||
|
|
||||||
# Local time zone for this installation. Choices can be found here:
|
# Local time zone for this installation. Choices can be found here:
|
||||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||||
TIME_ZONE = 'UTC'
|
TIME_ZONE = "UTC"
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
|
|
||||||
# Make this unique, and don't share it with anybody.
|
# Make this unique, and don't share it with anybody.
|
||||||
SECRET_KEY = ''
|
SECRET_KEY = ""
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# I18N
|
# I18N
|
||||||
|
@ -49,8 +49,8 @@ ALLOWED_HOSTS = ['*']
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
USE_L10N = False
|
USE_L10N = False
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en'
|
LANGUAGE_CODE = "en"
|
||||||
LANGUAGES = (('en', 'English'),)
|
LANGUAGES = (("en", "English"),)
|
||||||
|
|
||||||
# LOCALE_PATHS = (
|
# LOCALE_PATHS = (
|
||||||
# os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'locale')),
|
# os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'locale')),
|
||||||
|
@ -61,59 +61,59 @@ LANGUAGES = (('en', 'English'),)
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
STATICFILES_STORAGE = (
|
STATICFILES_STORAGE = (
|
||||||
'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
"django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||||
)
|
)
|
||||||
|
|
||||||
STATIC_ROOT = os.path.join(VAR_ROOT, 'static')
|
STATIC_ROOT = os.path.join(VAR_ROOT, "static")
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
ADMIN_MEDIA_PREFIX = "/static/admin/"
|
||||||
|
|
||||||
ROOT_URLCONF = 'dpaste.urls'
|
ROOT_URLCONF = "dpaste.urls"
|
||||||
|
|
||||||
LOGIN_URL = '/accounts/login/'
|
LOGIN_URL = "/accounts/login/"
|
||||||
LOGOUT_URL = '/accounts/logout/'
|
LOGOUT_URL = "/accounts/logout/"
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = "/"
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Templates
|
# Templates
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'django.middleware.common.CommonMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
"django.middleware.locale.LocaleMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'csp.middleware.CSPMiddleware',
|
"csp.middleware.CSPMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
'DIRS': [],
|
"DIRS": [],
|
||||||
'APP_DIRS': True,
|
"APP_DIRS": True,
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.template.context_processors.i18n',
|
"django.template.context_processors.i18n",
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'django.contrib.staticfiles',
|
"django.contrib.staticfiles",
|
||||||
'django.contrib.sessions',
|
"django.contrib.sessions",
|
||||||
'staticinline.apps.StaticInlineAppConfig',
|
"staticinline.apps.StaticInlineAppConfig",
|
||||||
'dpaste.apps.dpasteAppConfig',
|
"dpaste.apps.dpasteAppConfig",
|
||||||
]
|
]
|
||||||
|
|
||||||
# DATABASES = {
|
# DATABASES = {
|
||||||
|
@ -132,7 +132,7 @@ INSTALLED_APPS = [
|
||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
CSRF_COOKIE_SECURE = True
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
SECURE_BROWSER_XSS_FILTER = True
|
SECURE_BROWSER_XSS_FILTER = True
|
||||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||||
|
|
||||||
|
@ -141,23 +141,23 @@ CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'")
|
||||||
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
|
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
"version": 1,
|
||||||
'disable_existing_loggers': False,
|
"disable_existing_loggers": False,
|
||||||
'filters': {
|
"filters": {
|
||||||
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
|
"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}
|
||||||
},
|
},
|
||||||
'handlers': {
|
"handlers": {
|
||||||
'mail_admins': {
|
"mail_admins": {
|
||||||
'level': 'ERROR',
|
"level": "ERROR",
|
||||||
'filters': ['require_debug_false'],
|
"filters": ["require_debug_false"],
|
||||||
'class': 'django.utils.log.AdminEmailHandler',
|
"class": "django.utils.log.AdminEmailHandler",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'loggers': {
|
"loggers": {
|
||||||
'django.request': {
|
"django.request": {
|
||||||
'handlers': ['mail_admins'],
|
"handlers": ["mail_admins"],
|
||||||
'level': 'ERROR',
|
"level": "ERROR",
|
||||||
'propagate': True,
|
"propagate": True,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ if not 'runsslserver' in sys.argv:
|
||||||
#
|
#
|
||||||
|
|
||||||
# from dpaste.apps import dpasteAppConfig
|
# from dpaste.apps import dpasteAppConfig
|
||||||
# from django.utils.translation import ugettext_lazy as _
|
# from django.utils.translation import gettext_lazy as _
|
||||||
#
|
#
|
||||||
# class ProductionDpasteAppConfig(dpasteAppConfig):
|
# class ProductionDpasteAppConfig(dpasteAppConfig):
|
||||||
# SLUG_LENGTH = 8
|
# SLUG_LENGTH = 8
|
||||||
|
|
|
@ -5,13 +5,13 @@ import django
|
||||||
|
|
||||||
from .base import *
|
from .base import *
|
||||||
|
|
||||||
SECRET_KEY = 'test-key'
|
SECRET_KEY = "test-key"
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}
|
"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Drop CSP middleware for Django 3.0 until it was fixed upstream
|
# Drop CSP middleware for Django 3.0 until it was fixed upstream
|
||||||
# https://github.com/mozilla/django-csp/issues/129
|
# https://github.com/mozilla/django-csp/issues/129
|
||||||
if django.get_version().startswith('3.'):
|
if django.get_version().startswith("3."):
|
||||||
MIDDLEWARE.remove('csp.middleware.CSPMiddleware')
|
MIDDLEWARE.remove("csp.middleware.CSPMiddleware")
|
||||||
|
|
|
@ -7,12 +7,12 @@ from django.urls import reverse
|
||||||
|
|
||||||
from ..models import Snippet
|
from ..models import Snippet
|
||||||
|
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
|
|
||||||
|
|
||||||
class SnippetAPITestCase(TestCase):
|
class SnippetAPITestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.api_url = reverse('dpaste_api_create_snippet')
|
self.api_url = reverse("dpaste_api_create_snippet")
|
||||||
self.client = Client(enforce_csrf_checks=True)
|
self.client = Client(enforce_csrf_checks=True)
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
|
@ -27,19 +27,19 @@ class SnippetAPITestCase(TestCase):
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
# No content
|
# No content
|
||||||
data['content'] = ''
|
data["content"] = ""
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
# Just some spaces
|
# Just some spaces
|
||||||
data['content'] = ' '
|
data["content"] = " "
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
# Linebreaks or tabs only are not valid either
|
# Linebreaks or tabs only are not valid either
|
||||||
data['content'] = '\n\t '
|
data["content"] = "\n\t "
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -48,10 +48,10 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
A valid snippet, contains Unicode, tabs, spaces, linebreaks etc.
|
A valid snippet, contains Unicode, tabs, spaces, linebreaks etc.
|
||||||
"""
|
"""
|
||||||
data = {'content': u"Hello Wörld.\n\tGood Bye"}
|
data = {"content": u"Hello Wörld.\n\tGood Bye"}
|
||||||
|
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode("utf-8")
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -65,36 +65,36 @@ class SnippetAPITestCase(TestCase):
|
||||||
response = self.client.get(content[1:-1])
|
response = self.client.get(content[1:-1])
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertContains(response, data['content'])
|
self.assertContains(response, data["content"])
|
||||||
|
|
||||||
def test_new_url_format(self):
|
def test_new_url_format(self):
|
||||||
"""
|
"""
|
||||||
The 'new' url format is just the link with a linebreak.
|
The 'new' url format is just the link with a linebreak.
|
||||||
"""
|
"""
|
||||||
data = {'content': u"Hello Wörld.\n\tGood Bye", 'format': 'url'}
|
data = {"content": u"Hello Wörld.\n\tGood Bye", "format": "url"}
|
||||||
|
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode("utf-8")
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
# Response is just the link starting with http(s) and ends with a linebreak
|
# Response is just the link starting with http(s) and ends with a linebreak
|
||||||
self.assertTrue(content.startswith('http'))
|
self.assertTrue(content.startswith("http"))
|
||||||
self.assertTrue(content.endswith('\n'))
|
self.assertTrue(content.endswith("\n"))
|
||||||
|
|
||||||
def test_json_format(self):
|
def test_json_format(self):
|
||||||
"""
|
"""
|
||||||
The 'new' url format is just the link with a linebreak.
|
The 'new' url format is just the link with a linebreak.
|
||||||
"""
|
"""
|
||||||
data = {
|
data = {
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'format': 'json',
|
"format": "json",
|
||||||
'lexer': 'haskell',
|
"lexer": "haskell",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode("utf-8")
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -104,9 +104,9 @@ class SnippetAPITestCase(TestCase):
|
||||||
json_data = loads(content)
|
json_data = loads(content)
|
||||||
|
|
||||||
# Response is valid json, containing, content, lexer and url
|
# Response is valid json, containing, content, lexer and url
|
||||||
self.assertEqual(json_data['content'], data['content'])
|
self.assertEqual(json_data["content"], data["content"])
|
||||||
self.assertEqual(json_data['lexer'], data['lexer'])
|
self.assertEqual(json_data["lexer"], data["lexer"])
|
||||||
self.assertTrue(json_data['url'].startswith('http'))
|
self.assertTrue(json_data["url"].startswith("http"))
|
||||||
|
|
||||||
def test_invalid_format(self):
|
def test_invalid_format(self):
|
||||||
"""
|
"""
|
||||||
|
@ -115,9 +115,9 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'format': 'broken-format',
|
"format": "broken-format",
|
||||||
'lexer': 'haskell',
|
"lexer": "haskell",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
|
@ -128,7 +128,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
A broken lexer will fail loudly.
|
A broken lexer will fail loudly.
|
||||||
"""
|
"""
|
||||||
data = {'content': u"Hello Wörld.\n\tGood Bye", 'lexer': 'foobar'}
|
data = {"content": u"Hello Wörld.\n\tGood Bye", "lexer": "foobar"}
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -136,7 +136,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_expire_choices_none_given(self):
|
def test_expire_choices_none_given(self):
|
||||||
# No expire choice given will set a default expiration of one month
|
# No expire choice given will set a default expiration of one month
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url, {'content': u"Hello Wörld.\n\tGood Bye"}
|
self.api_url, {"content": u"Hello Wörld.\n\tGood Bye"}
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -146,7 +146,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
# A expire choice that does not exist returns a BadRequest
|
# A expire choice that does not exist returns a BadRequest
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'foobar'},
|
{"content": u"Hello Wörld.\n\tGood Bye", "expires": "foobar"},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -159,7 +159,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_valid_expiration_choices_onetime(self):
|
def test_valid_expiration_choices_onetime(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'onetime'},
|
{"content": u"Hello Wörld.\n\tGood Bye", "expires": "onetime"},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -170,7 +170,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_valid_expiration_choices_never(self):
|
def test_valid_expiration_choices_never(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'never'},
|
{"content": u"Hello Wörld.\n\tGood Bye", "expires": "never"},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -181,7 +181,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_valid_expiration_choices_hour(self):
|
def test_valid_expiration_choices_hour(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600},
|
{"content": u"Hello Wörld.\n\tGood Bye", "expires": 3600},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -190,7 +190,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_valid_expiration_choices_week(self):
|
def test_valid_expiration_choices_week(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 7},
|
{"content": u"Hello Wörld.\n\tGood Bye", "expires": 3600 * 24 * 7},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -199,7 +199,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_valid_expiration_choices_month(self):
|
def test_valid_expiration_choices_month(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 30},
|
{"content": u"Hello Wörld.\n\tGood Bye", "expires": 3600 * 24 * 30},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -212,9 +212,9 @@ class SnippetAPITestCase(TestCase):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{
|
{
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'lexer': '',
|
"lexer": "",
|
||||||
'filename': '',
|
"filename": "",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
@ -226,14 +226,14 @@ class SnippetAPITestCase(TestCase):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{
|
{
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'lexer': '',
|
"lexer": "",
|
||||||
'filename': 'helloworld.py',
|
"filename": "helloworld.py",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
self.assertEqual(Snippet.objects.all()[0].lexer, 'python')
|
self.assertEqual(Snippet.objects.all()[0].lexer, "python")
|
||||||
|
|
||||||
def test_awkward_filename_given(self):
|
def test_awkward_filename_given(self):
|
||||||
"""
|
"""
|
||||||
|
@ -242,9 +242,9 @@ class SnippetAPITestCase(TestCase):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{
|
{
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'lexer': '',
|
"lexer": "",
|
||||||
'filename': 'helloworld.helloworld',
|
"filename": "helloworld.helloworld",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -260,19 +260,19 @@ class SnippetAPITestCase(TestCase):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
self.api_url,
|
self.api_url,
|
||||||
{
|
{
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'lexer': 'php',
|
"lexer": "php",
|
||||||
'filename': 'helloworld.py',
|
"filename": "helloworld.py",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
self.assertEqual(Snippet.objects.all()[0].lexer, 'php')
|
self.assertEqual(Snippet.objects.all()[0].lexer, "php")
|
||||||
|
|
||||||
def test_leading_white_is_retained(self):
|
def test_leading_white_is_retained(self):
|
||||||
"""
|
"""
|
||||||
Leading Whitespace is retained in the db.
|
Leading Whitespace is retained in the db.
|
||||||
"""
|
"""
|
||||||
content = ' one\n two\n three\n four'
|
content = " one\n two\n three\n four"
|
||||||
self.client.post(self.api_url, {'content': content})
|
self.client.post(self.api_url, {"content": content})
|
||||||
self.assertEqual(Snippet.objects.all()[0].content, content)
|
self.assertEqual(Snippet.objects.all()[0].content, content)
|
||||||
|
|
|
@ -16,7 +16,7 @@ class HighlightAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
PLAIN_CODE is not run through Pygments, test it separately.
|
PLAIN_CODE is not run through Pygments, test it separately.
|
||||||
"""
|
"""
|
||||||
input = 'vär'
|
input = "vär"
|
||||||
expected = '<span class="plain">vär</span>'
|
expected = '<span class="plain">vär</span>'
|
||||||
value = PlainCodeHighlighter().highlight(input)
|
value = PlainCodeHighlighter().highlight(input)
|
||||||
self.assertEqual(value, expected)
|
self.assertEqual(value, expected)
|
||||||
|
@ -25,7 +25,7 @@ class HighlightAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
Whitespace on the first line is retained.
|
Whitespace on the first line is retained.
|
||||||
"""
|
"""
|
||||||
input = ' vär=1'
|
input = " vär=1"
|
||||||
expected = '<span class="plain"> vär=1</span>'
|
expected = '<span class="plain"> vär=1</span>'
|
||||||
value = PlainCodeHighlighter().highlight(input)
|
value = PlainCodeHighlighter().highlight(input)
|
||||||
self.assertEqual(value, expected)
|
self.assertEqual(value, expected)
|
||||||
|
@ -34,7 +34,7 @@ class HighlightAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
Whitespace on the first line is retained, also on subsequent lines.
|
Whitespace on the first line is retained, also on subsequent lines.
|
||||||
"""
|
"""
|
||||||
input = ' vär=1\n' ' vär=2\n' ' vär=3\n' ' vär=4'
|
input = " vär=1\n" " vär=2\n" " vär=3\n" " vär=4"
|
||||||
expected = (
|
expected = (
|
||||||
'<span class="plain"> vär=1</span>\n'
|
'<span class="plain"> vär=1</span>\n'
|
||||||
'<span class="plain"> vär=2</span>\n'
|
'<span class="plain"> vär=2</span>\n'
|
||||||
|
@ -49,32 +49,32 @@ class HighlightAPITestCase(TestCase):
|
||||||
Pygemnts highlights the variable name, and also generally adds
|
Pygemnts highlights the variable name, and also generally adds
|
||||||
a trailing \n to all its result.
|
a trailing \n to all its result.
|
||||||
"""
|
"""
|
||||||
input = 'var'
|
input = "var"
|
||||||
expected = '<span class="n">var</span>\n'
|
expected = '<span class="n">var</span>\n'
|
||||||
value = PygmentsHighlighter().highlight(input, 'python')
|
value = PygmentsHighlighter().highlight(input, "python")
|
||||||
self.assertEqual(value, expected)
|
self.assertEqual(value, expected)
|
||||||
|
|
||||||
def test_pygments_leading_whitespace(self):
|
def test_pygments_leading_whitespace(self):
|
||||||
"""
|
"""
|
||||||
Whitespace on the first line is retained.
|
Whitespace on the first line is retained.
|
||||||
"""
|
"""
|
||||||
input = ' var'
|
input = " var"
|
||||||
expected = ' <span class="n">var</span>\n'
|
expected = ' <span class="n">var</span>\n'
|
||||||
value = PygmentsHighlighter().highlight(input, 'python')
|
value = PygmentsHighlighter().highlight(input, "python")
|
||||||
self.assertEqual(value, expected)
|
self.assertEqual(value, expected)
|
||||||
|
|
||||||
def test_pygments_leading_whitespace_multiline(self):
|
def test_pygments_leading_whitespace_multiline(self):
|
||||||
"""
|
"""
|
||||||
Whitespace on the first line is retained, also on subsequent lines.
|
Whitespace on the first line is retained, also on subsequent lines.
|
||||||
"""
|
"""
|
||||||
input = ' var\n' ' var\n' ' var\n' ' var'
|
input = " var\n" " var\n" " var\n" " var"
|
||||||
expected = (
|
expected = (
|
||||||
' <span class="n">var</span>\n'
|
' <span class="n">var</span>\n'
|
||||||
' <span class="n">var</span>\n'
|
' <span class="n">var</span>\n'
|
||||||
' <span class="n">var</span>\n'
|
' <span class="n">var</span>\n'
|
||||||
' <span class="n">var</span>\n'
|
' <span class="n">var</span>\n'
|
||||||
)
|
)
|
||||||
value = PygmentsHighlighter().highlight(input, 'python')
|
value = PygmentsHighlighter().highlight(input, "python")
|
||||||
self.assertEqual(value, expected)
|
self.assertEqual(value, expected)
|
||||||
|
|
||||||
def test_broken_rst_syntax(self):
|
def test_broken_rst_syntax(self):
|
||||||
|
@ -93,4 +93,4 @@ class HighlightAPITestCase(TestCase):
|
||||||
try:
|
try:
|
||||||
RestructuredTextHighlighter().highlight(input)
|
RestructuredTextHighlighter().highlight(input)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.fail('rst syntax raised unexpected exception: {}'.format(e))
|
self.fail(f"rst syntax raised unexpected exception: {e}")
|
||||||
|
|
|
@ -11,26 +11,26 @@ from django.urls import reverse
|
||||||
from ..highlight import PygmentsHighlighter
|
from ..highlight import PygmentsHighlighter
|
||||||
from ..models import Snippet
|
from ..models import Snippet
|
||||||
|
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
|
|
||||||
|
|
||||||
class SnippetTestCase(TestCase):
|
class SnippetTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.new_url = reverse('snippet_new')
|
self.new_url = reverse("snippet_new")
|
||||||
|
|
||||||
def valid_form_data(self, **kwargs):
|
def valid_form_data(self, **kwargs):
|
||||||
data = {
|
data = {
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
"content": u"Hello Wörld.\n\tGood Bye",
|
||||||
'lexer': config.LEXER_DEFAULT,
|
"lexer": config.LEXER_DEFAULT,
|
||||||
'expires': config.EXPIRE_DEFAULT,
|
"expires": config.EXPIRE_DEFAULT,
|
||||||
}
|
}
|
||||||
if kwargs:
|
if kwargs:
|
||||||
data.update(kwargs)
|
data.update(kwargs)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def test_about(self):
|
def test_about(self):
|
||||||
response = self.client.get(reverse('dpaste_about'))
|
response = self.client.get(reverse("dpaste_about"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
@ -47,17 +47,17 @@ class SnippetTestCase(TestCase):
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
|
|
||||||
# No content
|
# No content
|
||||||
data['content'] = ''
|
data["content"] = ""
|
||||||
self.client.post(self.new_url, data)
|
self.client.post(self.new_url, data)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
# Just some spaces
|
# Just some spaces
|
||||||
data['content'] = ' '
|
data["content"] = " "
|
||||||
self.client.post(self.new_url, data)
|
self.client.post(self.new_url, data)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
# Linebreaks or tabs only are not valid either
|
# Linebreaks or tabs only are not valid either
|
||||||
data['content'] = '\n\t '
|
data["content"] = "\n\t "
|
||||||
self.client.post(self.new_url, data)
|
self.client.post(self.new_url, data)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class SnippetTestCase(TestCase):
|
||||||
response = self.client.post(self.new_url, data, follow=True)
|
response = self.client.post(self.new_url, data, follow=True)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
self.assertContains(response, data['content'])
|
self.assertContains(response, data["content"])
|
||||||
|
|
||||||
# The unicode method contains the snippet id so we can easily print
|
# The unicode method contains the snippet id so we can easily print
|
||||||
# the id using {{ snippet }}
|
# the id using {{ snippet }}
|
||||||
|
@ -80,7 +80,7 @@ class SnippetTestCase(TestCase):
|
||||||
def test_new_snippet_custom_lexer(self):
|
def test_new_snippet_custom_lexer(self):
|
||||||
# You can pass a lexer key in GET.l
|
# You can pass a lexer key in GET.l
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
url = '%s?l=haskell' % self.new_url
|
url = "%s?l=haskell" % self.new_url
|
||||||
response = self.client.post(url, data, follow=True)
|
response = self.client.post(url, data, follow=True)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -89,7 +89,7 @@ class SnippetTestCase(TestCase):
|
||||||
# If you pass an invalid key it wont fail and just fallback
|
# If you pass an invalid key it wont fail and just fallback
|
||||||
# to the default lexer.
|
# to the default lexer.
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
url = '%s?l=invalid-lexer' % self.new_url
|
url = "%s?l=invalid-lexer" % self.new_url
|
||||||
response = self.client.post(url, data, follow=True)
|
response = self.client.post(url, data, follow=True)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -101,7 +101,7 @@ class SnippetTestCase(TestCase):
|
||||||
the snippet is considered as spam. We let the user know its spam.
|
the snippet is considered as spam. We let the user know its spam.
|
||||||
"""
|
"""
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
data['title'] = 'Any content'
|
data["title"] = "Any content"
|
||||||
response = self.client.post(self.new_url, data, follow=True)
|
response = self.client.post(self.new_url, data, follow=True)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -112,27 +112,27 @@ class SnippetTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
# POST data
|
# POST data
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
data['expires'] = 'onetime'
|
data["expires"] = "onetime"
|
||||||
|
|
||||||
# First view, the author gets redirected after posting
|
# First view, the author gets redirected after posting
|
||||||
response = self.client.post(self.new_url, data, follow=True)
|
response = self.client.post(self.new_url, data, follow=True)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
self.assertContains(response, data['content'])
|
self.assertContains(response, data["content"])
|
||||||
|
|
||||||
# Second View, another user looks at the snippet
|
# Second View, another user looks at the snippet
|
||||||
response = self.client.get(response.request['PATH_INFO'], follow=True)
|
response = self.client.get(response.request["PATH_INFO"], follow=True)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
self.assertContains(response, data['content'])
|
self.assertContains(response, data["content"])
|
||||||
|
|
||||||
# Third/Further View, another user looks at the snippet but it was deleted
|
# Third/Further View, another user looks at the snippet but it was deleted
|
||||||
response = self.client.get(response.request['PATH_INFO'], follow=True)
|
response = self.client.get(response.request["PATH_INFO"], follow=True)
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
def test_snippet_notfound(self):
|
def test_snippet_notfound(self):
|
||||||
url = reverse('snippet_details', kwargs={'snippet_id': 'abcd'})
|
url = reverse("snippet_details", kwargs={"snippet_id": "abcd"})
|
||||||
response = self.client.get(url, follow=True)
|
response = self.client.get(url, follow=True)
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
@ -143,18 +143,18 @@ class SnippetTestCase(TestCase):
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
response = self.client.post(self.new_url, data, follow=True)
|
response = self.client.post(self.new_url, data, follow=True)
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
response.request['PATH_INFO'], data, follow=True
|
response.request["PATH_INFO"], data, follow=True
|
||||||
)
|
)
|
||||||
self.assertContains(response, data['content'])
|
self.assertContains(response, data["content"])
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 2)
|
self.assertEqual(Snippet.objects.count(), 2)
|
||||||
|
|
||||||
def test_reply_invalid(self):
|
def test_reply_invalid(self):
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
response = self.client.post(self.new_url, data, follow=True)
|
response = self.client.post(self.new_url, data, follow=True)
|
||||||
del data['content']
|
del data["content"]
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
response.request['PATH_INFO'], data, follow=True
|
response.request["PATH_INFO"], data, follow=True
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -170,8 +170,8 @@ class SnippetTestCase(TestCase):
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
|
|
||||||
snippet_id = Snippet.objects.all()[0].secret_id
|
snippet_id = Snippet.objects.all()[0].secret_id
|
||||||
url = reverse('snippet_details', kwargs={'snippet_id': snippet_id})
|
url = reverse("snippet_details", kwargs={"snippet_id": snippet_id})
|
||||||
response = self.client.post(url, {'delete': 1}, follow=True)
|
response = self.client.post(url, {"delete": 1}, follow=True)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -180,8 +180,8 @@ class SnippetTestCase(TestCase):
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
|
|
||||||
url = reverse('snippet_details', kwargs={'snippet_id': 'doesnotexist'})
|
url = reverse("snippet_details", kwargs={"snippet_id": "doesnotexist"})
|
||||||
response = self.client.post(url, {'delete': 1}, follow=True)
|
response = self.client.post(url, {"delete": 1}, follow=True)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -192,7 +192,7 @@ class SnippetTestCase(TestCase):
|
||||||
|
|
||||||
# Do not pass delete=1
|
# Do not pass delete=1
|
||||||
snippet_id = Snippet.objects.all()[0].secret_id
|
snippet_id = Snippet.objects.all()[0].secret_id
|
||||||
url = reverse('snippet_details', kwargs={'snippet_id': snippet_id})
|
url = reverse("snippet_details", kwargs={"snippet_id": snippet_id})
|
||||||
response = self.client.post(url, {}, follow=True)
|
response = self.client.post(url, {}, follow=True)
|
||||||
|
|
||||||
# Returns regular snippet details page
|
# Returns regular snippet details page
|
||||||
|
@ -210,7 +210,7 @@ class SnippetTestCase(TestCase):
|
||||||
|
|
||||||
# Next time its fetched its automatically deleted.
|
# Next time its fetched its automatically deleted.
|
||||||
snippet_id = Snippet.objects.all()[0].secret_id
|
snippet_id = Snippet.objects.all()[0].secret_id
|
||||||
url = reverse('snippet_details', kwargs={'snippet_id': snippet_id})
|
url = reverse("snippet_details", kwargs={"snippet_id": snippet_id})
|
||||||
response = self.client.get(url, follow=True)
|
response = self.client.get(url, follow=True)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
@ -224,19 +224,19 @@ class SnippetTestCase(TestCase):
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse(
|
reverse(
|
||||||
'snippet_details_raw',
|
"snippet_details_raw",
|
||||||
kwargs={'snippet_id': Snippet.objects.all()[0].secret_id},
|
kwargs={"snippet_id": Snippet.objects.all()[0].secret_id},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertContains(response, data['content'])
|
self.assertContains(response, data["content"])
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# XSS and correct escaping
|
# XSS and correct escaping
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
XSS_ORIGINAL = '<script>hello</script>'
|
XSS_ORIGINAL = "<script>hello</script>"
|
||||||
XSS_ESCAPED = '<script>hello</script>'
|
XSS_ESCAPED = "<script>hello</script>"
|
||||||
|
|
||||||
def test_xss_text_lexer(self):
|
def test_xss_text_lexer(self):
|
||||||
# Simple 'text' lexer
|
# Simple 'text' lexer
|
||||||
|
@ -256,7 +256,7 @@ class SnippetTestCase(TestCase):
|
||||||
|
|
||||||
def test_xss_pygments_lexer(self):
|
def test_xss_pygments_lexer(self):
|
||||||
# Pygments based lexer
|
# Pygments based lexer
|
||||||
data = self.valid_form_data(content=self.XSS_ORIGINAL, lexer='python')
|
data = self.valid_form_data(content=self.XSS_ORIGINAL, lexer="python")
|
||||||
response = self.client.post(self.new_url, data, follow=True)
|
response = self.client.post(self.new_url, data, follow=True)
|
||||||
self.assertContains(response, self.XSS_ESCAPED)
|
self.assertContains(response, self.XSS_ESCAPED)
|
||||||
|
|
||||||
|
@ -264,13 +264,13 @@ class SnippetTestCase(TestCase):
|
||||||
# History
|
# History
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
def test_snippet_history(self):
|
def test_snippet_history(self):
|
||||||
response = self.client.get(reverse('snippet_history'))
|
response = self.client.get(reverse("snippet_history"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
response = self.client.get(reverse('snippet_history'))
|
response = self.client.get(reverse("snippet_history"))
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
@ -278,7 +278,7 @@ class SnippetTestCase(TestCase):
|
||||||
def test_snippet_history_delete_all(self):
|
def test_snippet_history_delete_all(self):
|
||||||
# Empty list, delete all raises no error
|
# Empty list, delete all raises no error
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('snippet_history'), {'delete': 1}, follow=True
|
reverse("snippet_history"), {"delete": 1}, follow=True
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -292,7 +292,7 @@ class SnippetTestCase(TestCase):
|
||||||
|
|
||||||
# Delete all of them
|
# Delete all of them
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('snippet_history'), {'delete': 1}, follow=True
|
reverse("snippet_history"), {"delete": 1}, follow=True
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
@ -316,11 +316,11 @@ class SnippetTestCase(TestCase):
|
||||||
|
|
||||||
# You can call the management command with --dry-run which will
|
# You can call the management command with --dry-run which will
|
||||||
# list snippets to delete, but wont actually do.
|
# list snippets to delete, but wont actually do.
|
||||||
management.call_command('cleanup_snippets', dry_run=True)
|
management.call_command("cleanup_snippets", dry_run=True)
|
||||||
self.assertEqual(Snippet.objects.count(), 2)
|
self.assertEqual(Snippet.objects.count(), 2)
|
||||||
|
|
||||||
# Calling the management command will delete this one
|
# Calling the management command will delete this one
|
||||||
management.call_command('cleanup_snippets')
|
management.call_command("cleanup_snippets")
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
def test_delete_management_snippet_that_never_expires_will_not_get_deleted(
|
def test_delete_management_snippet_that_never_expires_will_not_get_deleted(
|
||||||
|
@ -330,18 +330,18 @@ class SnippetTestCase(TestCase):
|
||||||
Snippets without an expiration date wont get deleted automatically.
|
Snippets without an expiration date wont get deleted automatically.
|
||||||
"""
|
"""
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
data['expires'] = 'never'
|
data["expires"] = "never"
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
|
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
management.call_command('cleanup_snippets')
|
management.call_command("cleanup_snippets")
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
def test_highlighting(self):
|
def test_highlighting(self):
|
||||||
# You can pass any lexer to the pygmentize function and it will
|
# You can pass any lexer to the pygmentize function and it will
|
||||||
# never fail loudly.
|
# never fail loudly.
|
||||||
PygmentsHighlighter().highlight('code', 'python')
|
PygmentsHighlighter().highlight("code", "python")
|
||||||
PygmentsHighlighter().highlight('code', 'doesnotexist')
|
PygmentsHighlighter().highlight("code", "doesnotexist")
|
||||||
|
|
||||||
def test_random_slug_generation(self):
|
def test_random_slug_generation(self):
|
||||||
"""
|
"""
|
||||||
|
@ -351,17 +351,17 @@ class SnippetTestCase(TestCase):
|
||||||
slugs are extended now.
|
slugs are extended now.
|
||||||
"""
|
"""
|
||||||
for i in range(0, 100):
|
for i in range(0, 100):
|
||||||
Snippet.objects.create(content='foobar')
|
Snippet.objects.create(content="foobar")
|
||||||
slug_list = Snippet.objects.values_list(
|
slug_list = Snippet.objects.values_list(
|
||||||
'secret_id', flat=True
|
"secret_id", flat=True
|
||||||
).order_by('published')
|
).order_by("published")
|
||||||
self.assertEqual(len(set(slug_list)), 100)
|
self.assertEqual(len(set(slug_list)), 100)
|
||||||
|
|
||||||
def test_leading_white_is_retained_in_db(self):
|
def test_leading_white_is_retained_in_db(self):
|
||||||
"""
|
"""
|
||||||
Leading Whitespace is retained in the db.
|
Leading Whitespace is retained in the db.
|
||||||
"""
|
"""
|
||||||
content = ' one\n two\n three\n four'
|
content = " one\n two\n three\n four"
|
||||||
data = self.valid_form_data(content=content)
|
data = self.valid_form_data(content=content)
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
self.assertEqual(Snippet.objects.all()[0].content, content)
|
self.assertEqual(Snippet.objects.all()[0].content, content)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include('dpaste.urls.dpaste_api')),
|
url(r"^", include("dpaste.urls.dpaste_api")),
|
||||||
url(r'^', include('dpaste.urls.dpaste')),
|
url(r"^", include("dpaste.urls.dpaste")),
|
||||||
url(r'^i18n/', include('django.conf.urls.i18n')),
|
url(r"^i18n/", include("django.conf.urls.i18n")),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Custom error handlers which load `dpaste/<code>.html` instead of `<code>.html`
|
# Custom error handlers which load `dpaste/<code>.html` instead of `<code>.html`
|
||||||
handler404 = 'dpaste.views.page_not_found'
|
handler404 = "dpaste.views.page_not_found"
|
||||||
handler500 = 'dpaste.views.server_error'
|
handler500 = "dpaste.views.server_error"
|
||||||
|
|
|
@ -6,37 +6,37 @@ from django.views.generic import TemplateView
|
||||||
|
|
||||||
from .. import views
|
from .. import views
|
||||||
|
|
||||||
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
|
L = getattr(settings, "DPASTE_SLUG_LENGTH", 4)
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
|
url(r"^$", views.SnippetView.as_view(), name="snippet_new"),
|
||||||
url(
|
url(
|
||||||
r'^about/$',
|
r"^about/$",
|
||||||
TemplateView.as_view(
|
TemplateView.as_view(
|
||||||
template_name='dpaste/about.html',
|
template_name="dpaste/about.html",
|
||||||
extra_context=config.extra_template_context,
|
extra_context=config.extra_template_context,
|
||||||
),
|
),
|
||||||
name='dpaste_about',
|
name="dpaste_about",
|
||||||
),
|
),
|
||||||
url(r'^history/$', views.SnippetHistory.as_view(), name='snippet_history'),
|
url(r"^history/$", views.SnippetHistory.as_view(), name="snippet_history"),
|
||||||
url(
|
url(
|
||||||
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L,
|
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$" % L,
|
||||||
views.SnippetDetailView.as_view(),
|
views.SnippetDetailView.as_view(),
|
||||||
name='snippet_details',
|
name="snippet_details",
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L,
|
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$" % L,
|
||||||
views.SnippetRawView.as_view(),
|
views.SnippetRawView.as_view(),
|
||||||
name='snippet_details_raw',
|
name="snippet_details_raw",
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/slim/?$' % L,
|
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/slim/?$" % L,
|
||||||
xframe_options_exempt(
|
xframe_options_exempt(
|
||||||
views.SnippetDetailView.as_view(
|
views.SnippetDetailView.as_view(
|
||||||
template_name='dpaste/details_slim.html'
|
template_name="dpaste/details_slim.html"
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
name='snippet_details_slim',
|
name="snippet_details_slim",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,8 +5,8 @@ from ..views import APIView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(
|
url(
|
||||||
r'^api/$',
|
r"^api/$",
|
||||||
csrf_exempt(APIView.as_view()),
|
csrf_exempt(APIView.as_view()),
|
||||||
name='dpaste_api_create_snippet',
|
name="dpaste_api_create_snippet",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
100
dpaste/views.py
100
dpaste/views.py
|
@ -27,7 +27,7 @@ from dpaste.forms import SnippetForm, get_expire_values
|
||||||
from dpaste.highlight import PygmentsHighlighter
|
from dpaste.highlight import PygmentsHighlighter
|
||||||
from dpaste.models import Snippet
|
from dpaste.models import Snippet
|
||||||
|
|
||||||
config = apps.get_app_config('dpaste')
|
config = apps.get_app_config("dpaste")
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
@ -41,11 +41,11 @@ class SnippetView(FormView):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
form_class = SnippetForm
|
form_class = SnippetForm
|
||||||
template_name = 'dpaste/new.html'
|
template_name = "dpaste/new.html"
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super(SnippetView, self).get_form_kwargs()
|
kwargs = super(SnippetView, self).get_form_kwargs()
|
||||||
kwargs.update({'request': self.request})
|
kwargs.update({"request": self.request})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -65,9 +65,9 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = Snippet.objects.all()
|
queryset = Snippet.objects.all()
|
||||||
template_name = 'dpaste/details.html'
|
template_name = "dpaste/details.html"
|
||||||
slug_url_kwarg = 'snippet_id'
|
slug_url_kwarg = "snippet_id"
|
||||||
slug_field = 'secret_id'
|
slug_field = "secret_id"
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -76,14 +76,14 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
reasons and the chance to abuse this is not given anyway, since snippets
|
reasons and the chance to abuse this is not given anyway, since snippets
|
||||||
always expire.
|
always expire.
|
||||||
"""
|
"""
|
||||||
if 'delete' in self.request.POST:
|
if "delete" in self.request.POST:
|
||||||
snippet = get_object_or_404(
|
snippet = get_object_or_404(
|
||||||
Snippet, secret_id=self.kwargs['snippet_id']
|
Snippet, secret_id=self.kwargs["snippet_id"]
|
||||||
)
|
)
|
||||||
snippet.delete()
|
snippet.delete()
|
||||||
|
|
||||||
# Append `#` so #delete goes away in Firefox
|
# Append `#` so #delete goes away in Firefox
|
||||||
url = '{0}#'.format(reverse('snippet_new'))
|
url = "{0}#".format(reverse("snippet_new"))
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
return super(SnippetDetailView, self).post(request, *args, **kwargs)
|
return super(SnippetDetailView, self).post(request, *args, **kwargs)
|
||||||
|
@ -104,16 +104,16 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
|
|
||||||
# Increase the view count of the snippet
|
# Increase the view count of the snippet
|
||||||
snippet.view_count += 1
|
snippet.view_count += 1
|
||||||
snippet.save(update_fields=['view_count'])
|
snippet.save(update_fields=["view_count"])
|
||||||
|
|
||||||
return super(SnippetDetailView, self).get(request, *args, **kwargs)
|
return super(SnippetDetailView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
snippet = self.get_object()
|
snippet = self.get_object()
|
||||||
return {
|
return {
|
||||||
'content': snippet.content,
|
"content": snippet.content,
|
||||||
'lexer': snippet.lexer,
|
"lexer": snippet.lexer,
|
||||||
'rtl': snippet.rtl,
|
"rtl": snippet.rtl,
|
||||||
}
|
}
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -132,12 +132,12 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
d = difflib.unified_diff(
|
d = difflib.unified_diff(
|
||||||
snippet.parent.content.splitlines(),
|
snippet.parent.content.splitlines(),
|
||||||
snippet.content.splitlines(),
|
snippet.content.splitlines(),
|
||||||
ugettext('Previous Snippet'),
|
ugettext("Previous Snippet"),
|
||||||
ugettext('Current Snippet'),
|
ugettext("Current Snippet"),
|
||||||
n=1,
|
n=1,
|
||||||
)
|
)
|
||||||
diff_code = '\n'.join(d).strip()
|
diff_code = "\n".join(d).strip()
|
||||||
highlighted = PygmentsHighlighter().render(diff_code, 'diff')
|
highlighted = PygmentsHighlighter().render(diff_code, "diff")
|
||||||
|
|
||||||
# Remove blank lines
|
# Remove blank lines
|
||||||
return highlighted
|
return highlighted
|
||||||
|
@ -148,9 +148,9 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
ctx = super(SnippetDetailView, self).get_context_data(**kwargs)
|
ctx = super(SnippetDetailView, self).get_context_data(**kwargs)
|
||||||
ctx.update(
|
ctx.update(
|
||||||
{
|
{
|
||||||
'wordwrap': self.object.lexer in highlight.LEXER_WORDWRAP,
|
"wordwrap": self.object.lexer in highlight.LEXER_WORDWRAP,
|
||||||
'diff': self.get_snippet_diff(),
|
"diff": self.get_snippet_diff(),
|
||||||
'raw_mode': config.RAW_MODE_ENABLED,
|
"raw_mode": config.RAW_MODE_ENABLED,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
ctx.update(config.extra_template_context)
|
ctx.update(config.extra_template_context)
|
||||||
|
@ -162,22 +162,20 @@ class SnippetRawView(SnippetDetailView):
|
||||||
Display the raw content of a snippet
|
Display the raw content of a snippet
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template_name = 'dpaste/raw.html'
|
template_name = "dpaste/raw.html"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not config.RAW_MODE_ENABLED:
|
if not config.RAW_MODE_ENABLED:
|
||||||
return HttpResponseForbidden(
|
return HttpResponseForbidden(
|
||||||
ugettext(
|
ugettext("This dpaste installation has Raw view mode disabled.")
|
||||||
'This dpaste installation has Raw view mode disabled.'
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return super(SnippetRawView, self).dispatch(request, *args, **kwargs)
|
return super(SnippetRawView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def render_plain_text(self, context, **response_kwargs):
|
def render_plain_text(self, context, **response_kwargs):
|
||||||
snippet = self.get_object()
|
snippet = self.get_object()
|
||||||
response = HttpResponse(snippet.content)
|
response = HttpResponse(snippet.content)
|
||||||
response['Content-Type'] = 'text/plain;charset=UTF-8'
|
response["Content-Type"] = "text/plain;charset=UTF-8"
|
||||||
response['X-Content-Type-Options'] = 'nosniff'
|
response["X-Content-Type-Options"] = "nosniff"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def render_to_response(self, context, **response_kwargs):
|
def render_to_response(self, context, **response_kwargs):
|
||||||
|
@ -199,26 +197,26 @@ class SnippetHistory(TemplateView):
|
||||||
session).
|
session).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template_name = 'dpaste/history.html'
|
template_name = "dpaste/history.html"
|
||||||
|
|
||||||
def get_user_snippets(self):
|
def get_user_snippets(self):
|
||||||
snippet_id_list = self.request.session.get('snippet_list', [])
|
snippet_id_list = self.request.session.get("snippet_list", [])
|
||||||
return Snippet.objects.filter(pk__in=snippet_id_list)
|
return Snippet.objects.filter(pk__in=snippet_id_list)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Delete all user snippets at once.
|
Delete all user snippets at once.
|
||||||
"""
|
"""
|
||||||
if 'delete' in self.request.POST:
|
if "delete" in self.request.POST:
|
||||||
self.get_user_snippets().delete()
|
self.get_user_snippets().delete()
|
||||||
|
|
||||||
# Append `#` so #delete goes away in Firefox
|
# Append `#` so #delete goes away in Firefox
|
||||||
url = '{0}#'.format(reverse('snippet_history'))
|
url = "{0}#".format(reverse("snippet_history"))
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
|
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
|
||||||
ctx.update({'snippet_list': self.get_user_snippets()})
|
ctx.update({"snippet_list": self.get_user_snippets()})
|
||||||
ctx.update(config.extra_template_context)
|
ctx.update(config.extra_template_context)
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
@ -238,7 +236,7 @@ class APIView(View):
|
||||||
The default response is the snippet URL wrapped in quotes.
|
The default response is the snippet URL wrapped in quotes.
|
||||||
"""
|
"""
|
||||||
base_url = config.get_base_url(request=self.request)
|
base_url = config.get_base_url(request=self.request)
|
||||||
return '"{url}{path}"'.format(url=base_url, path=s.get_absolute_url())
|
return f'"{base_url}{s.get_absolute_url()}"'
|
||||||
|
|
||||||
def _format_url(self, s):
|
def _format_url(self, s):
|
||||||
"""
|
"""
|
||||||
|
@ -246,7 +244,7 @@ class APIView(View):
|
||||||
no quotes, but a linebreak at the end.
|
no quotes, but a linebreak at the end.
|
||||||
"""
|
"""
|
||||||
base_url = config.get_base_url(request=self.request)
|
base_url = config.get_base_url(request=self.request)
|
||||||
return '{url}{path}\n'.format(url=base_url, path=s.get_absolute_url())
|
return f"{base_url}{s.get_absolute_url()}\n"
|
||||||
|
|
||||||
def _format_json(self, s):
|
def _format_json(self, s):
|
||||||
"""
|
"""
|
||||||
|
@ -255,37 +253,35 @@ class APIView(View):
|
||||||
base_url = config.get_base_url(request=self.request)
|
base_url = config.get_base_url(request=self.request)
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
{
|
{
|
||||||
'url': '{url}{path}'.format(
|
"url": f"{base_url}{s.get_absolute_url()}",
|
||||||
url=base_url, path=s.get_absolute_url()
|
"content": s.content,
|
||||||
),
|
"lexer": s.lexer,
|
||||||
'content': s.content,
|
|
||||||
'lexer': s.lexer,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
content = request.POST.get('content', '')
|
content = request.POST.get("content", "")
|
||||||
lexer = request.POST.get('lexer', highlight.LEXER_DEFAULT).strip()
|
lexer = request.POST.get("lexer", highlight.LEXER_DEFAULT).strip()
|
||||||
filename = request.POST.get('filename', '').strip()
|
filename = request.POST.get("filename", "").strip()
|
||||||
expires = request.POST.get('expires', '').strip()
|
expires = request.POST.get("expires", "").strip()
|
||||||
response_format = request.POST.get('format', 'default').strip()
|
response_format = request.POST.get("format", "default").strip()
|
||||||
|
|
||||||
if not content.strip():
|
if not content.strip():
|
||||||
return HttpResponseBadRequest('No content given')
|
return HttpResponseBadRequest("No content given")
|
||||||
|
|
||||||
# We need at least a lexer or a filename
|
# We need at least a lexer or a filename
|
||||||
if not lexer and not filename:
|
if not lexer and not filename:
|
||||||
return HttpResponseBadRequest(
|
return HttpResponseBadRequest(
|
||||||
'No lexer or filename given. Unable to '
|
"No lexer or filename given. Unable to "
|
||||||
'determine a highlight. Valid lexers are: %s'
|
"determine a highlight. Valid lexers are: %s"
|
||||||
% ', '.join(highlight.LEXER_KEYS)
|
% ", ".join(highlight.LEXER_KEYS)
|
||||||
)
|
)
|
||||||
|
|
||||||
# A lexer is given, check if its valid at all
|
# A lexer is given, check if its valid at all
|
||||||
if lexer and lexer not in highlight.LEXER_KEYS:
|
if lexer and lexer not in highlight.LEXER_KEYS:
|
||||||
return HttpResponseBadRequest(
|
return HttpResponseBadRequest(
|
||||||
'Invalid lexer "%s" given. Valid lexers are: %s'
|
'Invalid lexer "%s" given. Valid lexers are: %s'
|
||||||
% (lexer, ', '.join(highlight.LEXER_KEYS))
|
% (lexer, ", ".join(highlight.LEXER_KEYS))
|
||||||
)
|
)
|
||||||
|
|
||||||
# No lexer is given, but we have a filename, try to get the lexer
|
# No lexer is given, but we have a filename, try to get the lexer
|
||||||
|
@ -303,7 +299,7 @@ class APIView(View):
|
||||||
if expires not in expire_options:
|
if expires not in expire_options:
|
||||||
return HttpResponseBadRequest(
|
return HttpResponseBadRequest(
|
||||||
'Invalid expire choice "{}" given. Valid values are: {}'.format(
|
'Invalid expire choice "{}" given. Valid values are: {}'.format(
|
||||||
expires, ', '.join(expire_options)
|
expires, ", ".join(expire_options)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
expires, expire_type = get_expire_values(expires)
|
expires, expire_type = get_expire_values(expires)
|
||||||
|
@ -321,7 +317,7 @@ class APIView(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Custom formatter for the API response
|
# Custom formatter for the API response
|
||||||
formatter = getattr(self, '_format_{0}'.format(response_format), None)
|
formatter = getattr(self, f"_format_{response_format}", None)
|
||||||
if callable(formatter):
|
if callable(formatter):
|
||||||
return HttpResponse(formatter(snippet))
|
return HttpResponse(formatter(snippet))
|
||||||
|
|
||||||
|
@ -335,13 +331,13 @@ class APIView(View):
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def page_not_found(request, exception=None, template_name='dpaste/404.html'):
|
def page_not_found(request, exception=None, template_name="dpaste/404.html"):
|
||||||
return django_page_not_found(
|
return django_page_not_found(
|
||||||
request, exception, template_name=template_name
|
request, exception, template_name=template_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def server_error(request, template_name='dpaste/500.html'):
|
def server_error(request, template_name="dpaste/500.html"):
|
||||||
return django_server_error(
|
return django_server_error(
|
||||||
request, template_name=template_name
|
request, template_name=template_name
|
||||||
) # pragma: no cover
|
) # pragma: no cover
|
||||||
|
|
Loading…
Reference in a new issue