Quote cleanup, fStrings and Deprecation fixes.

This commit is contained in:
Martin Mahner 2019-12-07 07:20:52 +01:00
parent cd586f62fe
commit e54790c8f9
17 changed files with 411 additions and 415 deletions

View file

@ -10,5 +10,5 @@ docutils = "==0.15"
[scripts]
runserver = "sh -c \"./manage.py migrate && ./manage.py runserver 0:8000\""
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"

View file

@ -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],
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"

View file

@ -1,14 +1,14 @@
from django.apps import AppConfig, apps
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):
name = 'dpaste'
verbose_name = 'dpaste'
name = "dpaste"
verbose_name = "dpaste"
# 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.
# 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; }
# </style>
# """
EXTRA_HEAD_HTML = ''
EXTRA_HEAD_HTML = ""
# 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
@ -35,12 +35,12 @@ class dpasteAppConfig(AppConfig):
# This is intentionally missing l and I as they look too similar with
# sans-serif fonts.
SLUG_CHOICES = (
'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890'
"abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890"
)
# 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
LEXER_DEFAULT = 'python'
LEXER_DEFAULT = "python"
# Integer. Maximum number of bytes per snippet.
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
# expiration dropdown. Example::
#
# from django.utils.translation import ugettext_lazy as _
# from django.utils.translation import gettext_lazy as _
# DPASTE_EXPIRE_CHOICES = (
# (3600, _('In one hour')),
# (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
# these snippets::
#
# from django.utils.translation import ugettext_lazy as _
# from django.utils.translation import gettext_lazy as _
# DPASTE_EXPIRE_CHOICES = (
# (3600, _('In one hour')),
# ('never', _('Never')),
# )
EXPIRE_CHOICES = (
('onetime', _('One-Time snippet')),
(3600, _('In one hour')),
(3600 * 24 * 7, _('In one week')),
(3600 * 24 * 30, _('In one month')),
('never', _('Never')),
("onetime", _("One-Time snippet")),
(3600, _("In one hour")),
(3600 * 24 * 7, _("In one week")),
(3600 * 24 * 30, _("In one month")),
("never", _("Never")),
)
# 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
# expire choices::
#
# from django.utils.translation import ugettext_lazy as _
# from django.utils.translation import gettext_lazy as _
# DPASTE_EXPIRE_CHOICES = (
# ('onetime', _('One-Time snippet')),
# (3600, _('In one hour')),
@ -102,11 +102,11 @@ class dpasteAppConfig(AppConfig):
RAW_MODE_PLAIN_TEXT = True
# Lexers which have wordwrap enabled by default
LEXER_WORDWRAP = ('rst',)
LEXER_WORDWRAP = ("rst",)
# Key names of the default text and code lexer.
PLAIN_TEXT_SYMBOL = '_text'
PLAIN_CODE_SYMBOL = '_code'
PLAIN_TEXT_SYMBOL = "_text"
PLAIN_CODE_SYMBOL = "_code"
@property
def TEXT_FORMATTER(self):
@ -129,9 +129,9 @@ class dpasteAppConfig(AppConfig):
)
return [
(self.PLAIN_TEXT_SYMBOL, 'Plain Text', PlainTextHighlighter),
('_markdown', 'Markdown', MarkdownHighlighter),
('_rst', 'reStructuredText', RestructuredTextHighlighter),
(self.PLAIN_TEXT_SYMBOL, "Plain Text", PlainTextHighlighter),
("_markdown", "Markdown", MarkdownHighlighter),
("_rst", "reStructuredText", RestructuredTextHighlighter),
]
@property
@ -159,7 +159,7 @@ class dpasteAppConfig(AppConfig):
from jsx.lexer import JsxLexer
return [
(self.PLAIN_CODE_SYMBOL, 'Plain Code', PlainCodeHighlighter),
(self.PLAIN_CODE_SYMBOL, "Plain Code", PlainCodeHighlighter),
# ('abap', 'ABAP'),
# ('abnf', 'ABNF'),
# ('ada', 'Ada'),
@ -180,8 +180,8 @@ class dpasteAppConfig(AppConfig):
# ('antlr-ruby', 'ANTLR With Ruby Target'),
# ('apacheconf', 'ApacheConf'),
# ('apl', 'APL'),
('applescript', 'AppleScript'),
('arduino', 'Arduino'),
("applescript", "AppleScript"),
("arduino", "Arduino"),
# ('as', 'ActionScript'),
# ('as3', 'ActionScript 3'),
# ('aspectj', 'AspectJ'),
@ -192,8 +192,8 @@ class dpasteAppConfig(AppConfig):
# ('autoit', 'AutoIt'),
# ('awk', 'Awk'),
# ('basemake', 'Base Makefile'),
('bash', 'Bash'),
('bat', 'Batchfile'),
("bash", "Bash"),
("bat", "Batchfile"),
# ('bbcode', 'BBCode'),
# ('bc', 'BC'),
# ('befunge', 'Befunge'),
@ -207,7 +207,7 @@ class dpasteAppConfig(AppConfig):
# ('bro', 'Bro'),
# ('bst', 'BST'),
# ('bugs', 'BUGS'),
('c', 'C'),
("c", "C"),
# ('c-objdump', 'c-objdump'),
# ('ca65', 'ca65 assembler'),
# ('cadl', 'cADL'),
@ -226,15 +226,15 @@ class dpasteAppConfig(AppConfig):
# ('cirru', 'Cirru'),
# ('clay', 'Clay'),
# ('clean', 'Clean'),
('clojure', 'Clojure'),
("clojure", "Clojure"),
# ('clojurescript', 'ClojureScript'),
('cmake', 'CMake'),
("cmake", "CMake"),
# ('cobol', 'COBOL'),
# ('cobolfree', 'COBOLFree'),
('coffee-script', 'CoffeeScript'),
('common-lisp', 'Common Lisp'),
("coffee-script", "CoffeeScript"),
("common-lisp", "Common Lisp"),
# ('componentpascal', 'Component Pascal'),
('console', 'Console/Bash Session'),
("console", "Console/Bash Session"),
# ('control', 'Debian Control file'),
# ('coq', 'Coq'),
# ('cpp', 'C++'),
@ -244,11 +244,11 @@ class dpasteAppConfig(AppConfig):
# ('crmsh', 'Crmsh'),
# ('croc', 'Croc'),
# ('cryptol', 'Cryptol'),
('csharp', 'C#'),
("csharp", "C#"),
# ('csound', 'Csound Orchestra'),
# ('csound-document', 'Csound Document'),
# ('csound-score', 'Csound Score'),
('css', 'CSS'),
("css", "CSS"),
# ('css+django', 'CSS+Django/Jinja'),
# ('css+erb', 'CSS+Ruby'),
# ('css+genshitext', 'CSS+Genshi Text'),
@ -259,17 +259,17 @@ class dpasteAppConfig(AppConfig):
# ('css+php', 'CSS+PHP'),
# ('css+smarty', 'CSS+Smarty'),
# ('cucumber', 'Gherkin'),
('cuda', 'CUDA'),
("cuda", "CUDA"),
# ('cypher', 'Cypher'),
# ('cython', 'Cython'),
# ('d', 'D'),
# ('d-objdump', 'd-objdump'),
('dart', 'Dart'),
('delphi', 'Delphi'),
("dart", "Dart"),
("delphi", "Delphi"),
# ('dg', 'dg'),
('diff', 'Diff'),
('django', 'Django/Jinja'),
('docker', 'Docker'),
("diff", "Diff"),
("django", "Django/Jinja"),
("docker", "Docker"),
# ('doscon', 'MSDOS Session'),
# ('dpatch', 'Darcs Patch'),
# ('dtd', 'DTD'),
@ -283,12 +283,12 @@ class dpasteAppConfig(AppConfig):
# ('ec', 'eC'),
# ('ecl', 'ECL'),
# ('eiffel', 'Eiffel'),
('elixir', 'Elixir'),
("elixir", "Elixir"),
# ('elm', 'Elm'),
# ('emacs', 'EmacsLisp'),
# ('erb', 'ERB'),
# ('erl', 'Erlang erl session'),
('erlang', 'Erlang'),
("erlang", "Erlang"),
# ('evoque', 'Evoque'),
# ('extempore', 'xtlang'),
# ('ezhil', 'Ezhil'),
@ -310,7 +310,7 @@ class dpasteAppConfig(AppConfig):
# ('genshitext', 'Genshi Text'),
# ('glsl', 'GLSL'),
# ('gnuplot', 'Gnuplot'),
('go', 'Go'),
("go", "Go"),
# ('golo', 'Golo'),
# ('gooddata-cl', 'GoodData-CL'),
# ('gosu', 'Gosu'),
@ -318,15 +318,15 @@ class dpasteAppConfig(AppConfig):
# ('groovy', 'Groovy'),
# ('gst', 'Gosu Template'),
# ('haml', 'Haml'),
('handlebars', 'Handlebars'),
('haskell', 'Haskell'),
("handlebars", "Handlebars"),
("haskell", "Haskell"),
# ('haxeml', 'Hxml'),
# ('hexdump', 'Hexdump'),
# ('hlsl', 'HLSL'),
# ('hsail', 'HSAIL'),
('html', 'HTML'),
("html", "HTML"),
# ('html+cheetah', 'HTML+Cheetah'),
('html+django', 'HTML + Django/Jinja'),
("html+django", "HTML + Django/Jinja"),
# ('html+evoque', 'HTML+Evoque'),
# ('html+genshi', 'HTML+Genshi'),
# ('html+handlebars', 'HTML+Handlebars'),
@ -349,22 +349,22 @@ class dpasteAppConfig(AppConfig):
# ('igor', 'Igor'),
# ('inform6', 'Inform 6'),
# ('inform7', 'Inform 7'),
('ini', 'INI'),
("ini", "INI"),
# ('io', 'Io'),
# ('ioke', 'Ioke'),
# ('ipython2', 'IPython'),
# ('ipython3', 'IPython3'),
('ipythonconsole', 'IPython console session'),
('irc', 'IRC logs'),
("ipythonconsole", "IPython console session"),
("irc", "IRC logs"),
# ('isabelle', 'Isabelle'),
# ('j', 'J'),
# ('jags', 'JAGS'),
# ('jasmin', 'Jasmin'),
('java', 'Java'),
("java", "Java"),
# ('javascript+mozpreproc', 'Javascript+mozpreproc'),
# ('jcl', 'JCL'),
# ('jlcon', 'Julia console'),
('js', 'JavaScript'),
("js", "JavaScript"),
# ('js+cheetah', 'JavaScript+Cheetah'),
# ('js+django', 'JavaScript+Django/Jinja'),
# ('js+erb', 'JavaScript+Ruby'),
@ -375,8 +375,8 @@ class dpasteAppConfig(AppConfig):
# ('js+php', 'JavaScript+PHP'),
# ('js+smarty', 'JavaScript+Smarty'),
# ('jsgf', 'JSGF'),
('json', 'JSON'),
('jsx', 'JSX/React'),
("json", "JSON"),
("jsx", "JSX/React"),
# ('json-object', 'JSONBareObject'),
# ('jsonld', 'JSON-LD'),
# ('jsp', 'Java Server Page'),
@ -385,12 +385,12 @@ class dpasteAppConfig(AppConfig):
# ('kal', 'Kal'),
# ('kconfig', 'Kconfig'),
# ('koka', 'Koka'),
('kotlin', 'Kotlin'),
("kotlin", "Kotlin"),
# ('lagda', 'Literate Agda'),
# ('lasso', 'Lasso'),
# ('lcry', 'Literate Cryptol'),
# ('lean', 'Lean'),
('less', 'LessCSS'),
("less", "LessCSS"),
# ('lhs', 'Literate Haskell'),
# ('lidr', 'Literate Idris'),
# ('lighty', 'Lighttpd configuration file'),
@ -401,14 +401,14 @@ class dpasteAppConfig(AppConfig):
# ('logos', 'Logos'),
# ('logtalk', 'Logtalk'),
# ('lsl', 'LSL'),
('lua', 'Lua'),
('make', 'Makefile'),
("lua", "Lua"),
("make", "Makefile"),
# ('mako', 'Mako'),
# ('maql', 'MAQL'),
# ('mask', 'Mask'),
# ('mason', 'Mason'),
# ('mathematica', 'Mathematica'),
('matlab', 'Matlab'),
("matlab", "Matlab"),
# ('matlabsession', 'Matlab session'),
# ('md', 'markdown'),
# ('minid', 'MiniD'),
@ -433,16 +433,16 @@ class dpasteAppConfig(AppConfig):
# ('newlisp', 'NewLisp'),
# ('newspeak', 'Newspeak'),
# ('ng2', 'Angular2'),
('nginx', 'Nginx configuration file'),
("nginx", "Nginx configuration file"),
# ('nim', 'Nimrod'),
# ('nit', 'Nit'),
# ('nixos', 'Nix'),
# ('nsis', 'NSIS'),
('numpy', 'NumPy'),
("numpy", "NumPy"),
# ('nusmv', 'NuSMV'),
# ('objdump', 'objdump'),
# ('objdump-nasm', 'objdump-nasm'),
('objective-c', 'Objective-C'),
("objective-c", "Objective-C"),
# ('objective-c++', 'Objective-C++'),
# ('objective-j', 'Objective-J'),
# ('ocaml', 'OCaml'),
@ -455,14 +455,14 @@ class dpasteAppConfig(AppConfig):
# ('pan', 'Pan'),
# ('parasail', 'ParaSail'),
# ('pawn', 'Pawn'),
('perl', 'Perl'),
("perl", "Perl"),
# ('perl6', 'Perl6'),
('php', 'PHP'),
("php", "PHP"),
# ('pig', 'Pig'),
# ('pike', 'Pike'),
# ('pkgconfig', 'PkgConfig'),
# ('plpgsql', 'PL/pgSQL'),
('postgresql', 'PostgreSQL SQL dialect'),
("postgresql", "PostgreSQL SQL dialect"),
# ('postscript', 'PostScript'),
# ('pot', 'Gettext Catalog'),
# ('pov', 'POVRay'),
@ -479,7 +479,7 @@ class dpasteAppConfig(AppConfig):
# ('pycon', 'Python console session'),
# ('pypylog', 'PyPy Log'),
# ('pytb', 'Python Traceback'),
('python', 'Python'),
("python", "Python"),
# ('python3', 'Python 3'),
# ('qbasic', 'QBasic'),
# ('qml', 'QML'),
@ -494,7 +494,7 @@ class dpasteAppConfig(AppConfig):
# ('ragel-objc', 'Ragel in Objective C Host'),
# ('ragel-ruby', 'Ragel in Ruby Host'),
# ('raw', 'Raw token data'),
('rb', 'Ruby'),
("rb", "Ruby"),
# ('rbcon', 'Ruby irb session'),
# ('rconsole', 'RConsole'),
# ('rd', 'Rd'),
@ -511,17 +511,17 @@ class dpasteAppConfig(AppConfig):
# ('robotframework', 'RobotFramework'),
# ('rql', 'RQL'),
# ('rsl', 'RSL'),
('rst', 'reStructuredText'),
("rst", "reStructuredText"),
# ('rts', 'TrafficScript'),
('rust', 'Rust'),
("rust", "Rust"),
# ('sas', 'SAS'),
('sass', 'Sass'),
("sass", "Sass"),
# ('sc', 'SuperCollider'),
# ('scala', 'Scala'),
# ('scaml', 'Scaml'),
# ('scheme', 'Scheme'),
# ('scilab', 'Scilab'),
('scss', 'SCSS'),
("scss", "SCSS"),
# ('shen', 'Shen'),
# ('silver', 'Silver'),
# ('slim', 'Slim'),
@ -531,19 +531,19 @@ class dpasteAppConfig(AppConfig):
# ('sml', 'Standard ML'),
# ('snobol', 'Snobol'),
# ('snowball', 'Snowball'),
('sol', 'Solidity'),
("sol", "Solidity"),
# ('sourceslist', 'Debian Sourcelist'),
# ('sp', 'SourcePawn'),
# ('sparql', 'SPARQL'),
# ('spec', 'RPMSpec'),
# ('splus', 'S'),
('sql', 'SQL'),
("sql", "SQL"),
# ('sqlite3', 'sqlite3con'),
# ('squidconf', 'SquidConf'),
# ('ssp', 'Scalate Server Page'),
# ('stan', 'Stan'),
# ('stata', 'Stata'),
('swift', 'Swift'),
("swift", "Swift"),
# ('swig', 'SWIG'),
# ('systemverilog', 'systemverilog'),
# ('tads3', 'TADS 3'),
@ -556,7 +556,7 @@ class dpasteAppConfig(AppConfig):
# ('termcap', 'Termcap'),
# ('terminfo', 'Terminfo'),
# ('terraform', 'Terraform'),
('tex', 'TeX'),
("tex", "TeX"),
# ('text', 'Text only'),
# ('thrift', 'Thrift'),
# ('todotxt', 'Todotxt'),
@ -566,7 +566,7 @@ class dpasteAppConfig(AppConfig):
# ('tsql', 'Transact-SQL'),
# ('turtle', 'Turtle'),
# ('twig', 'Twig'),
('typoscript', 'TypoScript'),
("typoscript", "TypoScript"),
# ('typoscriptcssdata', 'TypoScriptCssData'),
# ('typoscripthtmldata', 'TypoScriptHtmlData'),
# ('urbiscript', 'UrbiScript'),
@ -579,11 +579,11 @@ class dpasteAppConfig(AppConfig):
# ('verilog', 'verilog'),
# ('vgl', 'VGL'),
# ('vhdl', 'vhdl'),
('vim', 'VimL'),
("vim", "VimL"),
# ('wdiff', 'WDiff'),
# ('whiley', 'Whiley'),
# ('x10', 'X10'),
('xml', 'XML'),
("xml", "XML"),
# ('xml+cheetah', 'XML+Cheetah'),
# ('xml+django', 'XML+Django/Jinja'),
# ('xml+erb', 'XML+Ruby'),
@ -596,10 +596,10 @@ class dpasteAppConfig(AppConfig):
# ('xml+velocity', 'XML+Velocity'),
# ('xorg.conf', 'Xorg'),
# ('xquery', 'XQuery'),
('xslt', 'XSLT'),
("xslt", "XSLT"),
# ('xtend', 'Xtend'),
# ('xul+mozpreproc', 'XUL+mozpreproc'),
('yaml', 'YAML'),
("yaml", "YAML"),
# ('yaml+jinja', 'YAML+Jinja'),
# ('zephir', 'Zephir')
]
@ -612,13 +612,13 @@ class dpasteAppConfig(AppConfig):
framework is installed, it uses the current Site domain. Otherwise
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
site = get_current_site(request)
if site:
return 'https://{0}'.format(site.domain)
return 'https://dpaste.de'
return f"https://{site.domain}"
return "https://dpaste.de"
@property
def extra_template_context(self):
@ -627,6 +627,6 @@ class dpasteAppConfig(AppConfig):
all Template Views.
"""
return {
'dpaste_application_name': self.APPLICATION_NAME,
'dpaste_extra_head_html': mark_safe(self.EXTRA_HEAD_HTML),
"dpaste_application_name": self.APPLICATION_NAME,
"dpaste_extra_head_html": mark_safe(self.EXTRA_HEAD_HTML),
}

View file

@ -2,19 +2,19 @@ import datetime
from django import forms
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 .models import Snippet
config = apps.get_app_config('dpaste')
config = apps.get_app_config("dpaste")
def get_expire_values(expires):
if expires == 'never':
if expires == "never":
expire_type = Snippet.EXPIRE_KEEP
expires = None
elif expires == 'onetime':
elif expires == "onetime":
expire_type = Snippet.EXPIRE_ONETIME
expires = None
else:
@ -28,63 +28,63 @@ def get_expire_values(expires):
class SnippetForm(forms.ModelForm):
content = forms.CharField(
label=_('Content'),
label=_("Content"),
widget=forms.Textarea(
attrs={'placeholder': _('Awesome code goes here...')}
attrs={"placeholder": _("Awesome code goes here...")}
),
max_length=config.MAX_CONTENT_LENGTH,
strip=False,
)
lexer = forms.ChoiceField(
label=_('Lexer'), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
label=_("Lexer"), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
)
expires = forms.ChoiceField(
label=_('Expires'),
label=_("Expires"),
choices=config.EXPIRE_CHOICES,
initial=config.EXPIRE_DEFAULT,
)
rtl = forms.BooleanField(label=_('Right to Left'), required=False)
rtl = forms.BooleanField(label=_("Right to Left"), required=False)
# Honeypot field
title = forms.CharField(
label=_('Title'),
label=_("Title"),
required=False,
widget=forms.TextInput(attrs={'autocomplete': 'off'}),
widget=forms.TextInput(attrs={"autocomplete": "off"}),
)
class Meta:
model = Snippet
fields = ('content', 'lexer', 'rtl')
fields = ("content", "lexer", "rtl")
def __init__(self, request, *args, **kwargs):
super(SnippetForm, self).__init__(*args, **kwargs)
self.request = request
# 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:
self.fields['lexer'].initial = session_lexer
self.fields["lexer"].initial = session_lexer
# if the lexer is given via GET, set it
if 'l' in request.GET and request.GET['l'] in LEXER_KEYS:
self.fields['lexer'].initial = request.GET['l']
if "l" in request.GET and request.GET["l"] in LEXER_KEYS:
self.fields["lexer"].initial = request.GET["l"]
def clean_content(self):
content = self.cleaned_data.get('content', '')
content = self.cleaned_data.get("content", "")
if not content.strip():
raise forms.ValidationError(_('This field is required.'))
raise forms.ValidationError(_("This field is required."))
return content
def clean_expires(self):
"""
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)
self.cleaned_data['expire_type'] = expire_type
self.cleaned_data["expire_type"] = expire_type
return expires
def clean(self):
@ -92,8 +92,8 @@ class SnippetForm(forms.ModelForm):
The `title` field is a hidden honeypot field. If its filled,
this is likely spam.
"""
if self.cleaned_data.get('title'):
raise forms.ValidationError('This snippet was identified as Spam.')
if self.cleaned_data.get("title"):
raise forms.ValidationError("This snippet was identified as Spam.")
return self.cleaned_data
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
# null state of the db column for that.
self.instance.expires = self.cleaned_data['expires']
self.instance.expire_type = self.cleaned_data['expire_type']
self.instance.expires = self.cleaned_data["expires"]
self.instance.expire_type = self.cleaned_data["expire_type"]
# Save snippet in the db
super(SnippetForm, self).save(*args, **kwargs)
# Add the snippet to the user session list
self.request.session.setdefault('snippet_list', [])
self.request.session['snippet_list'] += [self.instance.pk]
self.request.session.setdefault("snippet_list", [])
self.request.session["snippet_list"] += [self.instance.pk]
# 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

View file

@ -4,7 +4,7 @@ from django.apps import apps
from django.template.defaultfilters import escape, linebreaksbr
from django.template.loader import render_to_string
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.formatters.html import HtmlFormatter
from pygments.lexers import get_lexer_by_name
@ -12,7 +12,7 @@ from pygments.lexers.python import PythonLexer
from pygments.util import ClassNotFound
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):
template_name = 'dpaste/highlight/code.html'
template_name = "dpaste/highlight/code.html"
def highlight(self, code_string, lexer_name=None):
"""Subclasses need to override this."""
return code_string
@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:
if l[0] == lexer_name:
return l[1]
@ -37,11 +37,11 @@ class Highlighter(object):
def render(self, code_string, lexer_name, direction=None, **kwargs):
highlighted_string = self.highlight(code_string, lexer_name=lexer_name)
context = {
'highlighted': highlighted_string,
'highlighted_splitted': highlighted_string.splitlines(),
'lexer_name': lexer_name,
'lexer_display_name': self.get_lexer_display_name(lexer_name),
'direction': direction,
"highlighted": highlighted_string,
"highlighted_splitted": highlighted_string.splitlines(),
"lexer_name": lexer_name,
"lexer_display_name": self.get_lexer_display_name(lexer_name),
"direction": direction,
}
context.update(kwargs)
return render_to_string(self.template_name, context)
@ -50,7 +50,7 @@ class Highlighter(object):
class PlainTextHighlighter(Highlighter):
"""Plain Text. Just replace linebreaks."""
template_name = 'dpaste/highlight/text.html'
template_name = "dpaste/highlight/text.html"
def highlight(self, code_string, **kwargs):
return linebreaksbr(code_string)
@ -60,17 +60,17 @@ class MarkdownHighlighter(PlainTextHighlighter):
"""Markdown"""
extensions = (
'tables',
'fenced-code',
'footnotes',
'autolink,',
'strikethrough',
'underline',
'quote',
'superscript',
'math',
"tables",
"fenced-code",
"footnotes",
"autolink,",
"strikethrough",
"underline",
"quote",
"superscript",
"math",
)
render_flags = ('skip-html',)
render_flags = ("skip-html",)
def highlight(self, code_string, **kwargs):
import misaka
@ -87,22 +87,22 @@ class MarkdownHighlighter(PlainTextHighlighter):
class RestructuredTextHighlighter(PlainTextHighlighter):
"""Restructured Text"""
rst_part_name = 'html_body'
rst_part_name = "html_body"
publish_args = {
'writer_name': 'html5_polyglot',
'settings_overrides': {
'raw_enabled': False,
'file_insertion_enabled': False,
'halt_level': 5,
'report_level': 2,
'warning_stream': '/dev/null',
"writer_name": "html5_polyglot",
"settings_overrides": {
"raw_enabled": False,
"file_insertion_enabled": False,
"halt_level": 5,
"report_level": 2,
"warning_stream": "/dev/null",
},
}
def highlight(self, code_string, **kwargs):
from docutils.core import publish_parts
self.publish_args['source'] = code_string
self.publish_args["source"] = code_string
parts = publish_parts(**self.publish_args)
return mark_safe(parts[self.rst_part_name])
@ -126,9 +126,9 @@ class PlainCodeHighlighter(Highlighter):
"""
def highlight(self, code_string, **kwargs):
return '\n'.join(
return "\n".join(
[
'<span class="plain">{}</span>'.format(escape(l) or '&#8203;')
'<span class="plain">{}</span>'.format(escape(l) or "&#8203;")
for l in code_string.splitlines()
]
)
@ -149,7 +149,7 @@ class PygmentsHighlighter(Highlighter):
try:
self.lexer = get_lexer_by_name(lexer_name)
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
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.
LEXER_CHOICES = (
(_('Text'), [i[:2] for i in config.TEXT_FORMATTER]),
(_('Code'), [i[:2] for i in config.CODE_FORMATTER]),
(_("Text"), [i[:2] for i in config.TEXT_FORMATTER]),
(_("Code"), [i[:2] for i in config.CODE_FORMATTER]),
)
# List of all Lexer Keys

View file

@ -9,10 +9,10 @@ class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
'--dry-run',
action='store_true',
dest='dry_run',
help='Don\'t do anything.',
"--dry-run",
action="store_true",
dest="dry_run",
help="Don't do anything.",
),
def handle(self, *args, **options):
@ -29,7 +29,7 @@ class Command(BaseCommand):
)
for d in deleteable_snippets:
self.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires))
if options.get('dry_run'):
self.stdout.write('Dry run - Not actually deleting snippets!\n')
if options.get("dry_run"):
self.stdout.write("Dry run - Not actually deleting snippets!\n")
else:
deleteable_snippets.delete()

View file

@ -4,12 +4,12 @@ from random import SystemRandom
from django.apps import apps
from django.db import models
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 dpaste import highlight
config = apps.get_app_config('dpaste')
config = apps.get_app_config("dpaste")
logger = getLogger(__file__)
R = SystemRandom()
@ -17,11 +17,11 @@ R = SystemRandom()
def generate_secret_id(length):
if length > config.SLUG_LENGTH:
logger.warning(
'Slug creation triggered a duplicate, '
'consider increasing the SLUG_LENGTH.'
"Slug creation triggered a duplicate, "
"consider increasing the SLUG_LENGTH."
)
secret_id = ''.join(
secret_id = "".join(
[
R.choice(config.SLUG_CHOICES)
for i in range(length or config.SLUG_LENGTH)
@ -45,37 +45,37 @@ class Snippet(models.Model):
EXPIRE_KEEP = 2
EXPIRE_ONETIME = 3
EXPIRE_CHOICES = (
(EXPIRE_TIME, _('Expire by timestamp')),
(EXPIRE_KEEP, _('Keep Forever')),
(EXPIRE_ONETIME, _('One-Time snippet')),
(EXPIRE_TIME, _("Expire by timestamp")),
(EXPIRE_KEEP, _("Keep Forever")),
(EXPIRE_ONETIME, _("One-Time snippet")),
)
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'), 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'), 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)
view_count = models.PositiveIntegerField(_('View count'), default=0)
rtl = models.BooleanField(_('Right-to-left'), default=False)
expires = models.DateTimeField(_("Expires"), blank=True, null=True)
view_count = models.PositiveIntegerField(_("View count"), default=0)
rtl = models.BooleanField(_("Right-to-left"), default=False)
parent = models.ForeignKey(
'self',
"self",
null=True,
blank=True,
verbose_name=_('Parent Snippet'),
related_name='children',
verbose_name=_("Parent Snippet"),
related_name="children",
on_delete=models.CASCADE,
)
class Meta:
ordering = ('-published',)
db_table = 'dpaste_snippet'
ordering = ("-published",)
db_table = "dpaste_snippet"
def __str__(self):
return self.secret_id
@ -86,14 +86,14 @@ class Snippet(models.Model):
super(Snippet, self).save(*args, **kwargs)
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):
HighlighterClass = highlight.get_highlighter_class(self.lexer)
return HighlighterClass().render(
code_string=self.content,
lexer_name=self.lexer,
direction='rtl' if self.rtl else 'ltr',
direction="rtl" if self.rtl else "ltr",
)
@property

View file

@ -14,17 +14,17 @@ PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split(
)
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/
# directory means that we're running in a virtual environment. Set the
# 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):
os.mkdir(VAR_ROOT)
else:
# Set the variable root to the local configuration location (which is
# 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
@ -34,13 +34,13 @@ DEBUG = False
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
TIME_ZONE = 'UTC'
TIME_ZONE = "UTC"
SITE_ID = 1
# Make this unique, and don't share it with anybody.
SECRET_KEY = ''
SECRET_KEY = ""
ALLOWED_HOSTS = ['*']
ALLOWED_HOSTS = ["*"]
# ==============================================================================
# I18N
@ -49,8 +49,8 @@ ALLOWED_HOSTS = ['*']
USE_I18N = True
USE_L10N = False
LANGUAGE_CODE = 'en'
LANGUAGES = (('en', 'English'),)
LANGUAGE_CODE = "en"
LANGUAGES = (("en", "English"),)
# LOCALE_PATHS = (
# os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'locale')),
@ -61,59 +61,59 @@ LANGUAGES = (('en', 'English'),)
# ==============================================================================
STATICFILES_STORAGE = (
'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
"django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
)
STATIC_ROOT = os.path.join(VAR_ROOT, 'static')
STATIC_ROOT = os.path.join(VAR_ROOT, "static")
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/'
STATIC_URL = "/static/"
ADMIN_MEDIA_PREFIX = "/static/admin/"
ROOT_URLCONF = 'dpaste.urls'
ROOT_URLCONF = "dpaste.urls"
LOGIN_URL = '/accounts/login/'
LOGOUT_URL = '/accounts/logout/'
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = "/accounts/login/"
LOGOUT_URL = "/accounts/logout/"
LOGIN_REDIRECT_URL = "/"
# ==============================================================================
# Templates
# ==============================================================================
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'csp.middleware.CSPMiddleware',
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.security.SecurityMiddleware",
"csp.middleware.CSPMiddleware",
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.i18n',
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.template.context_processors.i18n",
]
},
}
]
INSTALLED_APPS = [
'django.contrib.staticfiles',
'django.contrib.sessions',
'staticinline.apps.StaticInlineAppConfig',
'dpaste.apps.dpasteAppConfig',
"django.contrib.staticfiles",
"django.contrib.sessions",
"staticinline.apps.StaticInlineAppConfig",
"dpaste.apps.dpasteAppConfig",
]
# DATABASES = {
@ -132,7 +132,7 @@ INSTALLED_APPS = [
SESSION_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_CONTENT_TYPE_NOSNIFF = True
@ -141,23 +141,23 @@ CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'")
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
"version": 1,
"disable_existing_loggers": False,
"filters": {
"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler',
"handlers": {
"mail_admins": {
"level": "ERROR",
"filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
"loggers": {
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": True,
}
},
}

View file

@ -26,7 +26,7 @@ if not 'runsslserver' in sys.argv:
#
# from dpaste.apps import dpasteAppConfig
# from django.utils.translation import ugettext_lazy as _
# from django.utils.translation import gettext_lazy as _
#
# class ProductionDpasteAppConfig(dpasteAppConfig):
# SLUG_LENGTH = 8

View file

@ -5,13 +5,13 @@ import django
from .base import *
SECRET_KEY = 'test-key'
SECRET_KEY = "test-key"
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
# https://github.com/mozilla/django-csp/issues/129
if django.get_version().startswith('3.'):
MIDDLEWARE.remove('csp.middleware.CSPMiddleware')
if django.get_version().startswith("3."):
MIDDLEWARE.remove("csp.middleware.CSPMiddleware")

View file

@ -7,12 +7,12 @@ from django.urls import reverse
from ..models import Snippet
config = apps.get_app_config('dpaste')
config = apps.get_app_config("dpaste")
class SnippetAPITestCase(TestCase):
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)
def test_empty(self):
@ -27,19 +27,19 @@ class SnippetAPITestCase(TestCase):
self.assertEqual(Snippet.objects.count(), 0)
# No content
data['content'] = ''
data["content"] = ""
response = self.client.post(self.api_url, data)
self.assertEqual(response.status_code, 400)
self.assertEqual(Snippet.objects.count(), 0)
# Just some spaces
data['content'] = ' '
data["content"] = " "
response = self.client.post(self.api_url, data)
self.assertEqual(response.status_code, 400)
self.assertEqual(Snippet.objects.count(), 0)
# Linebreaks or tabs only are not valid either
data['content'] = '\n\t '
data["content"] = "\n\t "
response = self.client.post(self.api_url, data)
self.assertEqual(response.status_code, 400)
self.assertEqual(Snippet.objects.count(), 0)
@ -48,10 +48,10 @@ class SnippetAPITestCase(TestCase):
"""
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)
content = response.content.decode('utf-8')
content = response.content.decode("utf-8")
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
@ -65,36 +65,36 @@ class SnippetAPITestCase(TestCase):
response = self.client.get(content[1:-1])
self.assertEqual(response.status_code, 200)
self.assertContains(response, data['content'])
self.assertContains(response, data["content"])
def test_new_url_format(self):
"""
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)
content = response.content.decode('utf-8')
content = response.content.decode("utf-8")
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
# Response is just the link starting with http(s) and ends with a linebreak
self.assertTrue(content.startswith('http'))
self.assertTrue(content.endswith('\n'))
self.assertTrue(content.startswith("http"))
self.assertTrue(content.endswith("\n"))
def test_json_format(self):
"""
The 'new' url format is just the link with a linebreak.
"""
data = {
'content': u"Hello Wörld.\n\tGood Bye",
'format': 'json',
'lexer': 'haskell',
"content": u"Hello Wörld.\n\tGood Bye",
"format": "json",
"lexer": "haskell",
}
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(Snippet.objects.count(), 1)
@ -104,9 +104,9 @@ class SnippetAPITestCase(TestCase):
json_data = loads(content)
# Response is valid json, containing, content, lexer and url
self.assertEqual(json_data['content'], data['content'])
self.assertEqual(json_data['lexer'], data['lexer'])
self.assertTrue(json_data['url'].startswith('http'))
self.assertEqual(json_data["content"], data["content"])
self.assertEqual(json_data["lexer"], data["lexer"])
self.assertTrue(json_data["url"].startswith("http"))
def test_invalid_format(self):
"""
@ -115,9 +115,9 @@ class SnippetAPITestCase(TestCase):
"""
data = {
'content': u"Hello Wörld.\n\tGood Bye",
'format': 'broken-format',
'lexer': 'haskell',
"content": u"Hello Wörld.\n\tGood Bye",
"format": "broken-format",
"lexer": "haskell",
}
response = self.client.post(self.api_url, data)
@ -128,7 +128,7 @@ class SnippetAPITestCase(TestCase):
"""
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)
self.assertEqual(response.status_code, 400)
self.assertEqual(Snippet.objects.count(), 0)
@ -136,7 +136,7 @@ class SnippetAPITestCase(TestCase):
def test_expire_choices_none_given(self):
# No expire choice given will set a default expiration of one month
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(Snippet.objects.count(), 1)
@ -146,7 +146,7 @@ class SnippetAPITestCase(TestCase):
# A expire choice that does not exist returns a BadRequest
response = self.client.post(
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(Snippet.objects.count(), 0)
@ -159,7 +159,7 @@ class SnippetAPITestCase(TestCase):
def test_valid_expiration_choices_onetime(self):
response = self.client.post(
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(Snippet.objects.count(), 1)
@ -170,7 +170,7 @@ class SnippetAPITestCase(TestCase):
def test_valid_expiration_choices_never(self):
response = self.client.post(
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(Snippet.objects.count(), 1)
@ -181,7 +181,7 @@ class SnippetAPITestCase(TestCase):
def test_valid_expiration_choices_hour(self):
response = self.client.post(
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(Snippet.objects.count(), 1)
@ -190,7 +190,7 @@ class SnippetAPITestCase(TestCase):
def test_valid_expiration_choices_week(self):
response = self.client.post(
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(Snippet.objects.count(), 1)
@ -199,7 +199,7 @@ class SnippetAPITestCase(TestCase):
def test_valid_expiration_choices_month(self):
response = self.client.post(
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(Snippet.objects.count(), 1)
@ -212,9 +212,9 @@ class SnippetAPITestCase(TestCase):
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': '',
'filename': '',
"content": u"Hello Wörld.\n\tGood Bye",
"lexer": "",
"filename": "",
},
)
self.assertEqual(response.status_code, 400)
@ -226,14 +226,14 @@ class SnippetAPITestCase(TestCase):
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': '',
'filename': 'helloworld.py',
"content": u"Hello Wörld.\n\tGood Bye",
"lexer": "",
"filename": "helloworld.py",
},
)
self.assertEqual(response.status_code, 200)
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):
"""
@ -242,9 +242,9 @@ class SnippetAPITestCase(TestCase):
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': '',
'filename': 'helloworld.helloworld',
"content": u"Hello Wörld.\n\tGood Bye",
"lexer": "",
"filename": "helloworld.helloworld",
},
)
self.assertEqual(response.status_code, 200)
@ -260,19 +260,19 @@ class SnippetAPITestCase(TestCase):
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': 'php',
'filename': 'helloworld.py',
"content": u"Hello Wörld.\n\tGood Bye",
"lexer": "php",
"filename": "helloworld.py",
},
)
self.assertEqual(response.status_code, 200)
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):
"""
Leading Whitespace is retained in the db.
"""
content = ' one\n two\n three\n four'
self.client.post(self.api_url, {'content': content})
content = " one\n two\n three\n four"
self.client.post(self.api_url, {"content": content})
self.assertEqual(Snippet.objects.all()[0].content, content)

View file

@ -16,7 +16,7 @@ class HighlightAPITestCase(TestCase):
"""
PLAIN_CODE is not run through Pygments, test it separately.
"""
input = 'vär'
input = "vär"
expected = '<span class="plain">vär</span>'
value = PlainCodeHighlighter().highlight(input)
self.assertEqual(value, expected)
@ -25,7 +25,7 @@ class HighlightAPITestCase(TestCase):
"""
Whitespace on the first line is retained.
"""
input = ' vär=1'
input = " vär=1"
expected = '<span class="plain"> vär=1</span>'
value = PlainCodeHighlighter().highlight(input)
self.assertEqual(value, expected)
@ -34,7 +34,7 @@ class HighlightAPITestCase(TestCase):
"""
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 = (
'<span class="plain"> vär=1</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
a trailing \n to all its result.
"""
input = 'var'
input = "var"
expected = '<span class="n">var</span>\n'
value = PygmentsHighlighter().highlight(input, 'python')
value = PygmentsHighlighter().highlight(input, "python")
self.assertEqual(value, expected)
def test_pygments_leading_whitespace(self):
"""
Whitespace on the first line is retained.
"""
input = ' var'
input = " var"
expected = ' <span class="n">var</span>\n'
value = PygmentsHighlighter().highlight(input, 'python')
value = PygmentsHighlighter().highlight(input, "python")
self.assertEqual(value, expected)
def test_pygments_leading_whitespace_multiline(self):
"""
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 = (
' <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)
def test_broken_rst_syntax(self):
@ -93,4 +93,4 @@ class HighlightAPITestCase(TestCase):
try:
RestructuredTextHighlighter().highlight(input)
except Exception as e:
self.fail('rst syntax raised unexpected exception: {}'.format(e))
self.fail(f"rst syntax raised unexpected exception: {e}")

View file

@ -11,26 +11,26 @@ from django.urls import reverse
from ..highlight import PygmentsHighlighter
from ..models import Snippet
config = apps.get_app_config('dpaste')
config = apps.get_app_config("dpaste")
class SnippetTestCase(TestCase):
def setUp(self):
self.client = Client()
self.new_url = reverse('snippet_new')
self.new_url = reverse("snippet_new")
def valid_form_data(self, **kwargs):
data = {
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': config.LEXER_DEFAULT,
'expires': config.EXPIRE_DEFAULT,
"content": u"Hello Wörld.\n\tGood Bye",
"lexer": config.LEXER_DEFAULT,
"expires": config.EXPIRE_DEFAULT,
}
if kwargs:
data.update(kwargs)
return data
def test_about(self):
response = self.client.get(reverse('dpaste_about'))
response = self.client.get(reverse("dpaste_about"))
self.assertEqual(response.status_code, 200)
# -------------------------------------------------------------------------
@ -47,17 +47,17 @@ class SnippetTestCase(TestCase):
data = self.valid_form_data()
# No content
data['content'] = ''
data["content"] = ""
self.client.post(self.new_url, data)
self.assertEqual(Snippet.objects.count(), 0)
# Just some spaces
data['content'] = ' '
data["content"] = " "
self.client.post(self.new_url, data)
self.assertEqual(Snippet.objects.count(), 0)
# Linebreaks or tabs only are not valid either
data['content'] = '\n\t '
data["content"] = "\n\t "
self.client.post(self.new_url, data)
self.assertEqual(Snippet.objects.count(), 0)
@ -70,7 +70,7 @@ class SnippetTestCase(TestCase):
response = self.client.post(self.new_url, data, follow=True)
self.assertEqual(response.status_code, 200)
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 id using {{ snippet }}
@ -80,7 +80,7 @@ class SnippetTestCase(TestCase):
def test_new_snippet_custom_lexer(self):
# You can pass a lexer key in GET.l
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)
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
# to the default lexer.
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)
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.
"""
data = self.valid_form_data()
data['title'] = 'Any content'
data["title"] = "Any content"
response = self.client.post(self.new_url, data, follow=True)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 0)
@ -112,27 +112,27 @@ class SnippetTestCase(TestCase):
"""
# POST data
data = self.valid_form_data()
data['expires'] = 'onetime'
data["expires"] = "onetime"
# First view, the author gets redirected after posting
response = self.client.post(self.new_url, data, follow=True)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertContains(response, data['content'])
self.assertContains(response, data["content"])
# 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(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
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(Snippet.objects.count(), 0)
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)
self.assertEqual(response.status_code, 404)
@ -143,18 +143,18 @@ class SnippetTestCase(TestCase):
data = self.valid_form_data()
response = self.client.post(self.new_url, data, follow=True)
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(Snippet.objects.count(), 2)
def test_reply_invalid(self):
data = self.valid_form_data()
response = self.client.post(self.new_url, data, follow=True)
del data['content']
del data["content"]
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(Snippet.objects.count(), 1)
@ -170,8 +170,8 @@ class SnippetTestCase(TestCase):
self.client.post(self.new_url, data, follow=True)
snippet_id = Snippet.objects.all()[0].secret_id
url = reverse('snippet_details', kwargs={'snippet_id': snippet_id})
response = self.client.post(url, {'delete': 1}, follow=True)
url = reverse("snippet_details", kwargs={"snippet_id": snippet_id})
response = self.client.post(url, {"delete": 1}, follow=True)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 0)
@ -180,8 +180,8 @@ class SnippetTestCase(TestCase):
data = self.valid_form_data()
self.client.post(self.new_url, data, follow=True)
url = reverse('snippet_details', kwargs={'snippet_id': 'doesnotexist'})
response = self.client.post(url, {'delete': 1}, follow=True)
url = reverse("snippet_details", kwargs={"snippet_id": "doesnotexist"})
response = self.client.post(url, {"delete": 1}, follow=True)
self.assertEqual(response.status_code, 404)
self.assertEqual(Snippet.objects.count(), 1)
@ -192,7 +192,7 @@ class SnippetTestCase(TestCase):
# Do not pass delete=1
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)
# Returns regular snippet details page
@ -210,7 +210,7 @@ class SnippetTestCase(TestCase):
# Next time its fetched its automatically deleted.
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)
self.assertEqual(response.status_code, 404)
@ -224,19 +224,19 @@ class SnippetTestCase(TestCase):
self.client.post(self.new_url, data, follow=True)
response = self.client.get(
reverse(
'snippet_details_raw',
kwargs={'snippet_id': Snippet.objects.all()[0].secret_id},
"snippet_details_raw",
kwargs={"snippet_id": Snippet.objects.all()[0].secret_id},
)
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, data['content'])
self.assertContains(response, data["content"])
# -------------------------------------------------------------------------
# XSS and correct escaping
# -------------------------------------------------------------------------
XSS_ORIGINAL = '<script>hello</script>'
XSS_ESCAPED = '&lt;script&gt;hello&lt;/script&gt;'
XSS_ORIGINAL = "<script>hello</script>"
XSS_ESCAPED = "&lt;script&gt;hello&lt;/script&gt;"
def test_xss_text_lexer(self):
# Simple 'text' lexer
@ -256,7 +256,7 @@ class SnippetTestCase(TestCase):
def test_xss_pygments_lexer(self):
# 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)
self.assertContains(response, self.XSS_ESCAPED)
@ -264,13 +264,13 @@ class SnippetTestCase(TestCase):
# History
# -------------------------------------------------------------------------
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(Snippet.objects.count(), 0)
data = self.valid_form_data()
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(Snippet.objects.count(), 1)
@ -278,7 +278,7 @@ class SnippetTestCase(TestCase):
def test_snippet_history_delete_all(self):
# Empty list, delete all raises no error
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(Snippet.objects.count(), 0)
@ -292,7 +292,7 @@ class SnippetTestCase(TestCase):
# Delete all of them
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(Snippet.objects.count(), 0)
@ -316,11 +316,11 @@ class SnippetTestCase(TestCase):
# You can call the management command with --dry-run which will
# 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)
# Calling the management command will delete this one
management.call_command('cleanup_snippets')
management.call_command("cleanup_snippets")
self.assertEqual(Snippet.objects.count(), 1)
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.
"""
data = self.valid_form_data()
data['expires'] = 'never'
data["expires"] = "never"
self.client.post(self.new_url, data, follow=True)
self.assertEqual(Snippet.objects.count(), 1)
management.call_command('cleanup_snippets')
management.call_command("cleanup_snippets")
self.assertEqual(Snippet.objects.count(), 1)
def test_highlighting(self):
# You can pass any lexer to the pygmentize function and it will
# never fail loudly.
PygmentsHighlighter().highlight('code', 'python')
PygmentsHighlighter().highlight('code', 'doesnotexist')
PygmentsHighlighter().highlight("code", "python")
PygmentsHighlighter().highlight("code", "doesnotexist")
def test_random_slug_generation(self):
"""
@ -351,17 +351,17 @@ class SnippetTestCase(TestCase):
slugs are extended now.
"""
for i in range(0, 100):
Snippet.objects.create(content='foobar')
Snippet.objects.create(content="foobar")
slug_list = Snippet.objects.values_list(
'secret_id', flat=True
).order_by('published')
"secret_id", flat=True
).order_by("published")
self.assertEqual(len(set(slug_list)), 100)
def test_leading_white_is_retained_in_db(self):
"""
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)
self.client.post(self.new_url, data, follow=True)
self.assertEqual(Snippet.objects.all()[0].content, content)

View file

@ -1,11 +1,11 @@
from django.conf.urls import include, url
urlpatterns = [
url(r'^', include('dpaste.urls.dpaste_api')),
url(r'^', include('dpaste.urls.dpaste')),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r"^", include("dpaste.urls.dpaste_api")),
url(r"^", include("dpaste.urls.dpaste")),
url(r"^i18n/", include("django.conf.urls.i18n")),
]
# Custom error handlers which load `dpaste/<code>.html` instead of `<code>.html`
handler404 = 'dpaste.views.page_not_found'
handler500 = 'dpaste.views.server_error'
handler404 = "dpaste.views.page_not_found"
handler500 = "dpaste.views.server_error"

View file

@ -6,37 +6,37 @@ from django.views.generic import TemplateView
from .. import views
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
config = apps.get_app_config('dpaste')
L = getattr(settings, "DPASTE_SLUG_LENGTH", 4)
config = apps.get_app_config("dpaste")
urlpatterns = [
url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
url(r"^$", views.SnippetView.as_view(), name="snippet_new"),
url(
r'^about/$',
r"^about/$",
TemplateView.as_view(
template_name='dpaste/about.html',
template_name="dpaste/about.html",
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(
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L,
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$" % L,
views.SnippetDetailView.as_view(),
name='snippet_details',
name="snippet_details",
),
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(),
name='snippet_details_raw',
name="snippet_details_raw",
),
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(
views.SnippetDetailView.as_view(
template_name='dpaste/details_slim.html'
template_name="dpaste/details_slim.html"
)
),
name='snippet_details_slim',
name="snippet_details_slim",
),
]

View file

@ -5,8 +5,8 @@ from ..views import APIView
urlpatterns = [
url(
r'^api/$',
r"^api/$",
csrf_exempt(APIView.as_view()),
name='dpaste_api_create_snippet',
name="dpaste_api_create_snippet",
)
]

View file

@ -27,7 +27,7 @@ from dpaste.forms import SnippetForm, get_expire_values
from dpaste.highlight import PygmentsHighlighter
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
template_name = 'dpaste/new.html'
template_name = "dpaste/new.html"
def get_form_kwargs(self):
kwargs = super(SnippetView, self).get_form_kwargs()
kwargs.update({'request': self.request})
kwargs.update({"request": self.request})
return kwargs
def form_valid(self, form):
@ -65,9 +65,9 @@ class SnippetDetailView(SnippetView, DetailView):
"""
queryset = Snippet.objects.all()
template_name = 'dpaste/details.html'
slug_url_kwarg = 'snippet_id'
slug_field = 'secret_id'
template_name = "dpaste/details.html"
slug_url_kwarg = "snippet_id"
slug_field = "secret_id"
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
always expire.
"""
if 'delete' in self.request.POST:
if "delete" in self.request.POST:
snippet = get_object_or_404(
Snippet, secret_id=self.kwargs['snippet_id']
Snippet, secret_id=self.kwargs["snippet_id"]
)
snippet.delete()
# Append `#` so #delete goes away in Firefox
url = '{0}#'.format(reverse('snippet_new'))
url = "{0}#".format(reverse("snippet_new"))
return HttpResponseRedirect(url)
return super(SnippetDetailView, self).post(request, *args, **kwargs)
@ -104,16 +104,16 @@ class SnippetDetailView(SnippetView, DetailView):
# Increase the view count of the snippet
snippet.view_count += 1
snippet.save(update_fields=['view_count'])
snippet.save(update_fields=["view_count"])
return super(SnippetDetailView, self).get(request, *args, **kwargs)
def get_initial(self):
snippet = self.get_object()
return {
'content': snippet.content,
'lexer': snippet.lexer,
'rtl': snippet.rtl,
"content": snippet.content,
"lexer": snippet.lexer,
"rtl": snippet.rtl,
}
def form_valid(self, form):
@ -132,12 +132,12 @@ class SnippetDetailView(SnippetView, DetailView):
d = difflib.unified_diff(
snippet.parent.content.splitlines(),
snippet.content.splitlines(),
ugettext('Previous Snippet'),
ugettext('Current Snippet'),
ugettext("Previous Snippet"),
ugettext("Current Snippet"),
n=1,
)
diff_code = '\n'.join(d).strip()
highlighted = PygmentsHighlighter().render(diff_code, 'diff')
diff_code = "\n".join(d).strip()
highlighted = PygmentsHighlighter().render(diff_code, "diff")
# Remove blank lines
return highlighted
@ -148,9 +148,9 @@ class SnippetDetailView(SnippetView, DetailView):
ctx = super(SnippetDetailView, self).get_context_data(**kwargs)
ctx.update(
{
'wordwrap': self.object.lexer in highlight.LEXER_WORDWRAP,
'diff': self.get_snippet_diff(),
'raw_mode': config.RAW_MODE_ENABLED,
"wordwrap": self.object.lexer in highlight.LEXER_WORDWRAP,
"diff": self.get_snippet_diff(),
"raw_mode": config.RAW_MODE_ENABLED,
}
)
ctx.update(config.extra_template_context)
@ -162,22 +162,20 @@ class SnippetRawView(SnippetDetailView):
Display the raw content of a snippet
"""
template_name = 'dpaste/raw.html'
template_name = "dpaste/raw.html"
def dispatch(self, request, *args, **kwargs):
if not config.RAW_MODE_ENABLED:
return HttpResponseForbidden(
ugettext(
'This dpaste installation has Raw view mode disabled.'
)
ugettext("This dpaste installation has Raw view mode disabled.")
)
return super(SnippetRawView, self).dispatch(request, *args, **kwargs)
def render_plain_text(self, context, **response_kwargs):
snippet = self.get_object()
response = HttpResponse(snippet.content)
response['Content-Type'] = 'text/plain;charset=UTF-8'
response['X-Content-Type-Options'] = 'nosniff'
response["Content-Type"] = "text/plain;charset=UTF-8"
response["X-Content-Type-Options"] = "nosniff"
return response
def render_to_response(self, context, **response_kwargs):
@ -199,26 +197,26 @@ class SnippetHistory(TemplateView):
session).
"""
template_name = 'dpaste/history.html'
template_name = "dpaste/history.html"
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)
def post(self, request, *args, **kwargs):
"""
Delete all user snippets at once.
"""
if 'delete' in self.request.POST:
if "delete" in self.request.POST:
self.get_user_snippets().delete()
# Append `#` so #delete goes away in Firefox
url = '{0}#'.format(reverse('snippet_history'))
url = "{0}#".format(reverse("snippet_history"))
return HttpResponseRedirect(url)
def get_context_data(self, **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)
return ctx
@ -238,7 +236,7 @@ class APIView(View):
The default response is the snippet URL wrapped in quotes.
"""
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):
"""
@ -246,7 +244,7 @@ class APIView(View):
no quotes, but a linebreak at the end.
"""
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):
"""
@ -255,37 +253,35 @@ class APIView(View):
base_url = config.get_base_url(request=self.request)
return json.dumps(
{
'url': '{url}{path}'.format(
url=base_url, path=s.get_absolute_url()
),
'content': s.content,
'lexer': s.lexer,
"url": f"{base_url}{s.get_absolute_url()}",
"content": s.content,
"lexer": s.lexer,
}
)
def post(self, request, *args, **kwargs):
content = request.POST.get('content', '')
lexer = request.POST.get('lexer', highlight.LEXER_DEFAULT).strip()
filename = request.POST.get('filename', '').strip()
expires = request.POST.get('expires', '').strip()
response_format = request.POST.get('format', 'default').strip()
content = request.POST.get("content", "")
lexer = request.POST.get("lexer", highlight.LEXER_DEFAULT).strip()
filename = request.POST.get("filename", "").strip()
expires = request.POST.get("expires", "").strip()
response_format = request.POST.get("format", "default").strip()
if not content.strip():
return HttpResponseBadRequest('No content given')
return HttpResponseBadRequest("No content given")
# We need at least a lexer or a filename
if not lexer and not filename:
return HttpResponseBadRequest(
'No lexer or filename given. Unable to '
'determine a highlight. Valid lexers are: %s'
% ', '.join(highlight.LEXER_KEYS)
"No lexer or filename given. Unable to "
"determine a highlight. Valid lexers are: %s"
% ", ".join(highlight.LEXER_KEYS)
)
# A lexer is given, check if its valid at all
if lexer and lexer not in highlight.LEXER_KEYS:
return HttpResponseBadRequest(
'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
@ -303,7 +299,7 @@ class APIView(View):
if expires not in expire_options:
return HttpResponseBadRequest(
'Invalid expire choice "{}" given. Valid values are: {}'.format(
expires, ', '.join(expire_options)
expires, ", ".join(expire_options)
)
)
expires, expire_type = get_expire_values(expires)
@ -321,7 +317,7 @@ class APIView(View):
)
# 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):
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(
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(
request, template_name=template_name
) # pragma: no cover