mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 08:02:54 +11:00
Black'ed the entire codebase
black dpaste/ --skip-string-normalization --exclude="migrations"
This commit is contained in:
parent
3b85c0e910
commit
00c6f058b9
15 changed files with 248 additions and 202 deletions
|
@ -1,9 +1,7 @@
|
||||||
VERSION = (3, 0, 'a', 1)
|
VERSION = (3, 0, 'a', 1)
|
||||||
|
|
||||||
__version__ = '{major}.{minor}{rest}'.format(
|
__version__ = '{major}.{minor}{rest}'.format(
|
||||||
major=VERSION[0],
|
major=VERSION[0], minor=VERSION[1], rest=''.join(str(i) for i in VERSION[2:])
|
||||||
minor=VERSION[1],
|
|
||||||
rest=''.join(str(i) for i in VERSION[2:])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
default_app_config = 'dpaste.apps.dpasteAppConfig'
|
default_app_config = 'dpaste.apps.dpasteAppConfig'
|
||||||
|
|
|
@ -96,8 +96,9 @@ class dpasteAppConfig(AppConfig):
|
||||||
from dpaste.highlight import (
|
from dpaste.highlight import (
|
||||||
PlainTextHighlighter,
|
PlainTextHighlighter,
|
||||||
MarkdownHighlighter,
|
MarkdownHighlighter,
|
||||||
RestructuredTextHighlighter
|
RestructuredTextHighlighter,
|
||||||
)
|
)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(self.PLAIN_TEXT_SYMBOL, 'Plain Text', PlainTextHighlighter),
|
(self.PLAIN_TEXT_SYMBOL, 'Plain Text', PlainTextHighlighter),
|
||||||
('_markdown', 'Markdown', MarkdownHighlighter),
|
('_markdown', 'Markdown', MarkdownHighlighter),
|
||||||
|
@ -116,10 +117,8 @@ class dpasteAppConfig(AppConfig):
|
||||||
|
|
||||||
If the Highlight Class is not given, PygmentsHighlighter is used.
|
If the Highlight Class is not given, PygmentsHighlighter is used.
|
||||||
"""
|
"""
|
||||||
from dpaste.highlight import (
|
from dpaste.highlight import PlainCodeHighlighter, SolidityHighlighter
|
||||||
PlainCodeHighlighter,
|
|
||||||
SolidityHighlighter
|
|
||||||
)
|
|
||||||
return [
|
return [
|
||||||
(self.PLAIN_CODE_SYMBOL, 'Plain Code', PlainCodeHighlighter),
|
(self.PLAIN_CODE_SYMBOL, 'Plain Code', PlainCodeHighlighter),
|
||||||
('abap', 'ABAP'),
|
('abap', 'ABAP'),
|
||||||
|
@ -204,6 +203,7 @@ class dpasteAppConfig(AppConfig):
|
||||||
"""
|
"""
|
||||||
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 'https://{0}'.format(site.domain)
|
||||||
|
|
|
@ -29,34 +29,27 @@ class SnippetForm(forms.ModelForm):
|
||||||
label=_('Content'),
|
label=_('Content'),
|
||||||
widget=forms.Textarea(attrs={'placeholder': _('Awesome code goes here...')}),
|
widget=forms.Textarea(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'),
|
label=_('Lexer'), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
|
||||||
initial=LEXER_DEFAULT,
|
|
||||||
choices=LEXER_CHOICES
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expires = forms.ChoiceField(
|
expires = forms.ChoiceField(
|
||||||
label=_('Expires'),
|
label=_('Expires'), choices=config.EXPIRE_CHOICES, initial=config.EXPIRE_DEFAULT
|
||||||
choices=config.EXPIRE_CHOICES,
|
|
||||||
initial=config.EXPIRE_DEFAULT
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 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 = (
|
fields = ('content', 'lexer')
|
||||||
'content',
|
|
||||||
'lexer',
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(SnippetForm, self).__init__(*args, **kwargs)
|
super(SnippetForm, self).__init__(*args, **kwargs)
|
||||||
|
|
|
@ -19,6 +19,7 @@ config = apps.get_app_config('dpaste')
|
||||||
# Highlight Code Snippets
|
# Highlight Code Snippets
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class Highlighter(object):
|
class Highlighter(object):
|
||||||
template_name = 'dpaste/highlight/code.html'
|
template_name = 'dpaste/highlight/code.html'
|
||||||
|
|
||||||
|
@ -47,6 +48,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):
|
||||||
|
@ -55,20 +57,33 @@ class PlainTextHighlighter(Highlighter):
|
||||||
|
|
||||||
class MarkdownHighlighter(PlainTextHighlighter):
|
class MarkdownHighlighter(PlainTextHighlighter):
|
||||||
"""Markdown"""
|
"""Markdown"""
|
||||||
extensions = ('tables', 'fenced-code', 'footnotes', 'autolink,',
|
|
||||||
'strikethrough', 'underline', 'quote', 'superscript',
|
extensions = (
|
||||||
'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):
|
def highlight(self, code_string, **kwargs):
|
||||||
import misaka
|
import misaka
|
||||||
return mark_safe(misaka.html(code_string,
|
|
||||||
extensions=self.extensions,
|
return mark_safe(
|
||||||
render_flags=self.render_flags))
|
misaka.html(
|
||||||
|
code_string, extensions=self.extensions, render_flags=self.render_flags
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
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',
|
||||||
|
@ -78,11 +93,12 @@ class RestructuredTextHighlighter(PlainTextHighlighter):
|
||||||
'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])
|
||||||
|
@ -93,6 +109,7 @@ class RestructuredTextHighlighter(PlainTextHighlighter):
|
||||||
|
|
||||||
class NakedHtmlFormatter(HtmlFormatter):
|
class NakedHtmlFormatter(HtmlFormatter):
|
||||||
"""Pygments HTML formatter with no further HTML tags."""
|
"""Pygments HTML formatter with no further HTML tags."""
|
||||||
|
|
||||||
def wrap(self, source, outfile):
|
def wrap(self, source, outfile):
|
||||||
return self._wrap_code(source)
|
return self._wrap_code(source)
|
||||||
|
|
||||||
|
@ -105,11 +122,14 @@ class PlainCodeHighlighter(Highlighter):
|
||||||
"""
|
"""
|
||||||
Plain Code. No highlighting but Pygments like span tags around each line.
|
Plain Code. No highlighting but Pygments like span tags around each line.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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()
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PygmentsHighlighter(Highlighter):
|
class PygmentsHighlighter(Highlighter):
|
||||||
|
@ -117,6 +137,7 @@ class PygmentsHighlighter(Highlighter):
|
||||||
Highlight code string with Pygments. The lexer is automatically
|
Highlight code string with Pygments. The lexer is automatically
|
||||||
determined by the lexer name.
|
determined by the lexer name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
formatter = NakedHtmlFormatter()
|
formatter = NakedHtmlFormatter()
|
||||||
lexer = None
|
lexer = None
|
||||||
lexer_fallback = PythonLexer()
|
lexer_fallback = PythonLexer()
|
||||||
|
@ -139,6 +160,7 @@ class SolidityHighlighter(PygmentsHighlighter):
|
||||||
# SolidityLexer does not necessarily need to be installed
|
# SolidityLexer does not necessarily need to be installed
|
||||||
# since its imported here and not used later.
|
# since its imported here and not used later.
|
||||||
from pygments_lexer_solidity import SolidityLexer
|
from pygments_lexer_solidity import SolidityLexer
|
||||||
|
|
||||||
self.lexer = SolidityLexer()
|
self.lexer = SolidityLexer()
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,12 +189,13 @@ 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
|
||||||
LEXER_KEYS = [i[0] for i in config.TEXT_FORMATTER] + \
|
LEXER_KEYS = [i[0] for i in config.TEXT_FORMATTER] + [
|
||||||
[i[0] for i in config.CODE_FORMATTER]
|
i[0] for i in config.CODE_FORMATTER
|
||||||
|
]
|
||||||
|
|
||||||
# The default lexer which we fallback in case of
|
# The default lexer which we fallback in case of
|
||||||
# an error or if not supplied in an API call.
|
# an error or if not supplied in an API call.
|
||||||
|
|
|
@ -8,14 +8,15 @@ class Command(BaseCommand):
|
||||||
help = "Purges snippets that are expired"
|
help = "Purges snippets that are expired"
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('--dry-run', action='store_true', dest='dry_run',
|
parser.add_argument(
|
||||||
help='Don\'t do anything.'),
|
'--dry-run', action='store_true', dest='dry_run', help='Don\'t do anything.'
|
||||||
|
),
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
deleteable_snippets = Snippet.objects.filter(
|
deleteable_snippets = Snippet.objects.filter(
|
||||||
expires__isnull=False,
|
expires__isnull=False,
|
||||||
expire_type=Snippet.EXPIRE_TIME,
|
expire_type=Snippet.EXPIRE_TIME,
|
||||||
expires__lte=timezone.now()
|
expires__lte=timezone.now(),
|
||||||
)
|
)
|
||||||
if len(deleteable_snippets) == 0:
|
if len(deleteable_snippets) == 0:
|
||||||
self.stdout.write(u"No snippets to delete.")
|
self.stdout.write(u"No snippets to delete.")
|
||||||
|
|
|
@ -16,11 +16,14 @@ R = SystemRandom()
|
||||||
|
|
||||||
def generate_secret_id(length):
|
def generate_secret_id(length):
|
||||||
if length > config.SLUG_LENGTH:
|
if length > config.SLUG_LENGTH:
|
||||||
logger.warning('Slug creation triggered a duplicate, '
|
logger.warning(
|
||||||
'consider increasing the SLUG_LENGTH.')
|
'Slug creation triggered a duplicate, '
|
||||||
|
'consider increasing the SLUG_LENGTH.'
|
||||||
|
)
|
||||||
|
|
||||||
secret_id = ''.join([R.choice(config.SLUG_CHOICES)
|
secret_id = ''.join(
|
||||||
for i in range(length or config.SLUG_LENGTH)])
|
[R.choice(config.SLUG_CHOICES) for i in range(length or config.SLUG_LENGTH)]
|
||||||
|
)
|
||||||
|
|
||||||
# Check if this slug already exists, if not, return this new slug
|
# Check if this slug already exists, if not, return this new slug
|
||||||
try:
|
try:
|
||||||
|
@ -45,21 +48,24 @@ class Snippet(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
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 = models.PositiveIntegerField(_('View count'), default=0)
|
||||||
_('View count'), default=0)
|
|
||||||
parent = models.ForeignKey(
|
parent = models.ForeignKey(
|
||||||
'self', null=True, blank=True, verbose_name=_('Parent Snippet'),
|
'self',
|
||||||
related_name='children', on_delete=models.CASCADE)
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
verbose_name=_('Parent Snippet'),
|
||||||
|
related_name='children',
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('-published',)
|
ordering = ('-published',)
|
||||||
|
|
|
@ -49,9 +49,7 @@ USE_I18N = True
|
||||||
USE_L10N = False
|
USE_L10N = False
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en'
|
LANGUAGE_CODE = 'en'
|
||||||
LANGUAGES = (
|
LANGUAGES = (('en', 'English'),)
|
||||||
('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')),
|
||||||
|
@ -63,9 +61,7 @@ LANGUAGES = (
|
||||||
|
|
||||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||||
|
|
||||||
STATICFILES_DIRS = (
|
STATICFILES_DIRS = (os.path.join(PROJECT_DIR, 'build'),)
|
||||||
os.path.join(PROJECT_DIR, 'build'),
|
|
||||||
)
|
|
||||||
|
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
|
@ -107,9 +103,9 @@ TEMPLATES = [
|
||||||
'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 = [
|
||||||
|
@ -146,16 +142,12 @@ 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': {
|
||||||
|
@ -163,6 +155,6 @@ LOGGING = {
|
||||||
'handlers': ['mail_admins'],
|
'handlers': ['mail_admins'],
|
||||||
'level': 'ERROR',
|
'level': 'ERROR',
|
||||||
'propagate': True,
|
'propagate': True,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,9 +4,4 @@ Settings for the test suite
|
||||||
|
|
||||||
from .base import *
|
from .base import *
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}}
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
|
||||||
'NAME': ':memory:',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ 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)
|
||||||
|
@ -84,7 +83,6 @@ class SnippetAPITestCase(TestCase):
|
||||||
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.
|
||||||
|
@ -92,7 +90,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
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)
|
||||||
|
@ -102,6 +100,7 @@ class SnippetAPITestCase(TestCase):
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
from json import loads
|
from json import loads
|
||||||
|
|
||||||
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
|
||||||
|
@ -118,7 +117,7 @@ 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)
|
||||||
|
@ -129,26 +128,25 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
A broken lexer will fail loudly.
|
A broken lexer will fail loudly.
|
||||||
"""
|
"""
|
||||||
data = {
|
data = {'content': u"Hello Wörld.\n\tGood Bye", 'lexer': 'foobar'}
|
||||||
'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)
|
||||||
|
|
||||||
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(self.api_url, {
|
response = self.client.post(
|
||||||
'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)
|
||||||
self.assertTrue(Snippet.objects.all()[0].expires)
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
||||||
def test_expire_choices_invalid_given(self):
|
def test_expire_choices_invalid_given(self):
|
||||||
# A expire choice that does not exist returns a BadRequest
|
# A expire choice that does not exist returns a BadRequest
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'foobar'})
|
self.api_url, {'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)
|
||||||
|
|
||||||
|
@ -156,37 +154,45 @@ class SnippetAPITestCase(TestCase):
|
||||||
Test all the different expiration choices. We dont actually test
|
Test all the different expiration choices. We dont actually test
|
||||||
the deletion, since thats handled in the `test_snippet` section.
|
the deletion, since thats handled in the `test_snippet` section.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_valid_expiration_choices_onetime(self):
|
def test_valid_expiration_choices_onetime(self):
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'onetime'})
|
self.api_url, {'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)
|
||||||
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_ONETIME)
|
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_ONETIME)
|
||||||
|
|
||||||
def test_valid_expiration_choices_never(self):
|
def test_valid_expiration_choices_never(self):
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'never'})
|
self.api_url, {'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)
|
||||||
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_KEEP)
|
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_KEEP)
|
||||||
|
|
||||||
def test_valid_expiration_choices_hour(self):
|
def test_valid_expiration_choices_hour(self):
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600})
|
self.api_url, {'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)
|
||||||
self.assertTrue(Snippet.objects.all()[0].expires)
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
||||||
def test_valid_expiration_choices_week(self):
|
def test_valid_expiration_choices_week(self):
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 7})
|
self.api_url,
|
||||||
|
{'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)
|
||||||
self.assertTrue(Snippet.objects.all()[0].expires)
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
||||||
def test_valid_expiration_choices_month(self):
|
def test_valid_expiration_choices_month(self):
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 30})
|
self.api_url,
|
||||||
|
{'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)
|
||||||
self.assertTrue(Snippet.objects.all()[0].expires)
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
@ -195,22 +201,24 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
No lexer and no filename given returns a BadRequest.
|
No lexer and no filename given returns a BadRequest.
|
||||||
"""
|
"""
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
'content': u"Hello Wörld.\n\tGood Bye",
|
self.api_url,
|
||||||
'lexer': '',
|
{'content': u"Hello Wörld.\n\tGood Bye", 'lexer': '', 'filename': ''},
|
||||||
'filename': ''
|
)
|
||||||
})
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
def test_filename_given(self):
|
def test_filename_given(self):
|
||||||
"""
|
"""
|
||||||
No lexer and a Python filename will set a 'python' lexer.
|
No lexer and a Python filename will set a 'python' lexer.
|
||||||
"""
|
"""
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
|
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')
|
||||||
|
@ -219,11 +227,14 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
A unknown filename will create a 'plain' code snippet.
|
A unknown filename will create a 'plain' code snippet.
|
||||||
"""
|
"""
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
|
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)
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
self.assertEqual(Snippet.objects.all()[0].lexer, config.PLAIN_CODE_SYMBOL)
|
self.assertEqual(Snippet.objects.all()[0].lexer, config.PLAIN_CODE_SYMBOL)
|
||||||
|
@ -232,11 +243,14 @@ class SnippetAPITestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
A given lexer will overwrite whats the filename guessing.
|
A given lexer will overwrite whats the filename guessing.
|
||||||
"""
|
"""
|
||||||
response = self.client.post(self.api_url, {
|
response = self.client.post(
|
||||||
|
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')
|
||||||
|
@ -248,5 +262,3 @@ class SnippetAPITestCase(TestCase):
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,14 @@ from textwrap import dedent
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from dpaste.highlight import PlainCodeHighlighter, PygmentsHighlighter, \
|
from dpaste.highlight import (
|
||||||
RestructuredTextHighlighter
|
PlainCodeHighlighter,
|
||||||
|
PygmentsHighlighter,
|
||||||
|
RestructuredTextHighlighter,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class HighlightAPITestCase(TestCase):
|
class HighlightAPITestCase(TestCase):
|
||||||
|
|
||||||
def test_plain_code(self):
|
def test_plain_code(self):
|
||||||
"""
|
"""
|
||||||
PLAIN_CODE is not run through Pygments, test it separately.
|
PLAIN_CODE is not run through Pygments, test it separately.
|
||||||
|
@ -32,15 +34,13 @@ 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'
|
input = ' vär=1\n' ' vär=2\n' ' vär=3\n' ' vär=4'
|
||||||
' 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'
|
||||||
'<span class="plain"> vär=3</span>\n'
|
'<span class="plain"> vär=3</span>\n'
|
||||||
'<span class="plain"> vär=4</span>')
|
'<span class="plain"> vär=4</span>'
|
||||||
|
)
|
||||||
value = PlainCodeHighlighter().highlight(input)
|
value = PlainCodeHighlighter().highlight(input)
|
||||||
self.assertEqual(value, expected)
|
self.assertEqual(value, expected)
|
||||||
|
|
||||||
|
@ -67,15 +67,13 @@ 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 = (' var\n'
|
input = ' var\n' ' var\n' ' var\n' ' var'
|
||||||
' 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)
|
||||||
|
|
||||||
|
@ -84,12 +82,14 @@ class HighlightAPITestCase(TestCase):
|
||||||
rst Syntax thats not valid must not raise an exception (SystemMessage)
|
rst Syntax thats not valid must not raise an exception (SystemMessage)
|
||||||
"""
|
"""
|
||||||
# (SEVERE/4) Missing matching underline for section title overline.
|
# (SEVERE/4) Missing matching underline for section title overline.
|
||||||
input = dedent("""
|
input = dedent(
|
||||||
|
"""
|
||||||
=========================
|
=========================
|
||||||
Generate 15 random numbers
|
Generate 15 random numbers
|
||||||
70 180 3 179 192 117 75 72 90 190 49 159 63 14 55
|
70 180 3 179 192 117 75 72 90 190 49 159 63 14 55
|
||||||
=========================
|
=========================
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
RestructuredTextHighlighter().highlight(input)
|
RestructuredTextHighlighter().highlight(input)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -15,7 +15,6 @@ 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')
|
||||||
|
@ -132,7 +131,6 @@ class SnippetTestCase(TestCase):
|
||||||
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)
|
||||||
|
@ -203,8 +201,12 @@ class SnippetTestCase(TestCase):
|
||||||
def test_raw(self):
|
def test_raw(self):
|
||||||
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_details_raw', kwargs={
|
response = self.client.get(
|
||||||
'snippet_id': Snippet.objects.all()[0].secret_id}))
|
reverse(
|
||||||
|
'snippet_details_raw',
|
||||||
|
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'])
|
||||||
|
@ -217,22 +219,23 @@ class SnippetTestCase(TestCase):
|
||||||
|
|
||||||
def test_xss_text_lexer(self):
|
def test_xss_text_lexer(self):
|
||||||
# Simple 'text' lexer
|
# Simple 'text' lexer
|
||||||
data = self.valid_form_data(content=self.XSS_ORIGINAL,
|
data = self.valid_form_data(
|
||||||
lexer=config.PLAIN_TEXT_SYMBOL)
|
content=self.XSS_ORIGINAL, lexer=config.PLAIN_TEXT_SYMBOL
|
||||||
|
)
|
||||||
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)
|
||||||
|
|
||||||
def test_xss_code_lexer(self):
|
def test_xss_code_lexer(self):
|
||||||
# Simple 'code' lexer
|
# Simple 'code' lexer
|
||||||
data = self.valid_form_data(content=self.XSS_ORIGINAL,
|
data = self.valid_form_data(
|
||||||
lexer=config.PLAIN_CODE_SYMBOL)
|
content=self.XSS_ORIGINAL, lexer=config.PLAIN_CODE_SYMBOL
|
||||||
|
)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
data = self.valid_form_data(content=self.XSS_ORIGINAL, lexer='python')
|
||||||
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)
|
||||||
|
|
||||||
|
@ -253,8 +256,9 @@ 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(reverse('snippet_history'),
|
response = self.client.post(
|
||||||
{'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)
|
||||||
|
|
||||||
|
@ -266,8 +270,9 @@ class SnippetTestCase(TestCase):
|
||||||
self.assertEqual(Snippet.objects.count(), 2)
|
self.assertEqual(Snippet.objects.count(), 2)
|
||||||
|
|
||||||
# Delete all of them
|
# Delete all of them
|
||||||
response = self.client.post(reverse('snippet_history'),
|
response = self.client.post(
|
||||||
{'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)
|
||||||
|
|
||||||
|
@ -315,7 +320,6 @@ class SnippetTestCase(TestCase):
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
Set the max length of a slug to 1, so we wont have more than 60
|
Set the max length of a slug to 1, so we wont have more than 60
|
||||||
|
@ -325,8 +329,9 @@ class SnippetTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
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).order_by(
|
||||||
'secret_id', flat=True).order_by('published')
|
'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):
|
||||||
|
|
|
@ -7,18 +7,21 @@ from .. import views
|
||||||
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
|
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$',
|
url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
|
||||||
views.SnippetView.as_view(), name='snippet_new'),
|
url(
|
||||||
|
r'^about/$',
|
||||||
url(r'^about/$',
|
TemplateView.as_view(template_name='dpaste/about.html'),
|
||||||
TemplateView.as_view(template_name='dpaste/about.html'), name='dpaste_about'),
|
name='dpaste_about',
|
||||||
|
),
|
||||||
url(r'^history/$',
|
url(r'^history/$', views.SnippetHistory.as_view(), name='snippet_history'),
|
||||||
views.SnippetHistory.as_view(), name='snippet_history'),
|
url(
|
||||||
|
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L,
|
||||||
url(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(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L,
|
url(
|
||||||
views.SnippetRawView.as_view(), name='snippet_details_raw'),
|
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L,
|
||||||
|
views.SnippetRawView.as_view(),
|
||||||
|
name='snippet_details_raw',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,5 +4,5 @@ from django.views.decorators.csrf import csrf_exempt
|
||||||
from ..views import APIView
|
from ..views import APIView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^api/$', csrf_exempt(APIView.as_view()), name='dpaste_api_create_snippet'),
|
url(r'^api/$', csrf_exempt(APIView.as_view()), name='dpaste_api_create_snippet')
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,13 +3,19 @@ import difflib
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, \
|
from django.http import (
|
||||||
HttpResponseRedirect
|
Http404,
|
||||||
|
HttpResponse,
|
||||||
|
HttpResponseBadRequest,
|
||||||
|
HttpResponseRedirect,
|
||||||
|
)
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
from django.views.defaults import page_not_found as django_page_not_found, \
|
from django.views.defaults import (
|
||||||
server_error as django_server_error
|
page_not_found as django_page_not_found,
|
||||||
|
server_error as django_server_error,
|
||||||
|
)
|
||||||
from django.views.generic import FormView
|
from django.views.generic import FormView
|
||||||
from django.views.generic.base import TemplateView, View
|
from django.views.generic.base import TemplateView, View
|
||||||
from django.views.generic.detail import DetailView
|
from django.views.generic.detail import DetailView
|
||||||
|
@ -28,18 +34,18 @@ config = apps.get_app_config('dpaste')
|
||||||
# Snippet Handling
|
# Snippet Handling
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class SnippetView(FormView):
|
class SnippetView(FormView):
|
||||||
"""
|
"""
|
||||||
Create a new snippet.
|
Create a new snippet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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({
|
kwargs.update({'request': self.request})
|
||||||
'request': self.request,
|
|
||||||
})
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -52,6 +58,7 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
Details list view of a snippet. Handles the actual view, reply and
|
Details list view of a snippet. Handles the actual view, reply and
|
||||||
tree/diff view.
|
tree/diff view.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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'
|
||||||
|
@ -78,8 +85,10 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
snippet = self.get_object()
|
snippet = self.get_object()
|
||||||
|
|
||||||
# One-Time snippet get deleted if the view count matches our limit
|
# One-Time snippet get deleted if the view count matches our limit
|
||||||
if (snippet.expire_type == Snippet.EXPIRE_ONETIME and
|
if (
|
||||||
snippet.view_count >= config.ONETIME_LIMIT):
|
snippet.expire_type == Snippet.EXPIRE_ONETIME
|
||||||
|
and snippet.view_count >= config.ONETIME_LIMIT
|
||||||
|
):
|
||||||
snippet.delete()
|
snippet.delete()
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
@ -91,10 +100,7 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
snippet = self.get_object()
|
snippet = self.get_object()
|
||||||
return {
|
return {'content': snippet.content, 'lexer': snippet.lexer}
|
||||||
'content': snippet.content,
|
|
||||||
'lexer': snippet.lexer,
|
|
||||||
}
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
snippet = form.save(parent=self.get_object())
|
snippet = form.save(parent=self.get_object())
|
||||||
|
@ -114,7 +120,7 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
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')
|
||||||
|
@ -126,10 +132,12 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
|
|
||||||
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(),
|
||||||
})
|
}
|
||||||
|
)
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,6 +145,7 @@ class SnippetRawView(SnippetDetailView):
|
||||||
"""
|
"""
|
||||||
Display the raw content of a snippet
|
Display the raw content of a snippet
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def render_to_response(self, context, **response_kwargs):
|
def render_to_response(self, context, **response_kwargs):
|
||||||
snippet = self.get_object()
|
snippet = self.get_object()
|
||||||
response = HttpResponse(snippet.content)
|
response = HttpResponse(snippet.content)
|
||||||
|
@ -150,6 +159,7 @@ class SnippetHistory(TemplateView):
|
||||||
Display the last `n` snippets created by this user (and saved in his
|
Display the last `n` snippets created by this user (and saved in his
|
||||||
session).
|
session).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template_name = 'dpaste/history.html'
|
template_name = 'dpaste/history.html'
|
||||||
|
|
||||||
def get_user_snippets(self):
|
def get_user_snippets(self):
|
||||||
|
@ -169,9 +179,7 @@ class SnippetHistory(TemplateView):
|
||||||
|
|
||||||
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({
|
ctx.update({'snippet_list': self.get_user_snippets()})
|
||||||
'snippet_list': self.get_user_snippets(),
|
|
||||||
})
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,6 +192,7 @@ class APIView(View):
|
||||||
"""
|
"""
|
||||||
API View
|
API View
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _format_default(self, s):
|
def _format_default(self, s):
|
||||||
"""
|
"""
|
||||||
The default response is the snippet URL wrapped in quotes.
|
The default response is the snippet URL wrapped in quotes.
|
||||||
|
@ -204,11 +213,13 @@ class APIView(View):
|
||||||
The `json` format export.
|
The `json` format export.
|
||||||
"""
|
"""
|
||||||
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=base_url, path=s.get_absolute_url()),
|
'url': '{url}{path}'.format(url=base_url, path=s.get_absolute_url()),
|
||||||
'content': s.content,
|
'content': s.content,
|
||||||
'lexer': s.lexer,
|
'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', '')
|
||||||
|
@ -222,13 +233,18 @@ class APIView(View):
|
||||||
|
|
||||||
# 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('No lexer or filename given. Unable to '
|
return HttpResponseBadRequest(
|
||||||
'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
|
# 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('Invalid lexer "%s" given. Valid lexers are: %s' % (
|
return HttpResponseBadRequest(
|
||||||
lexer, ', '.join(highlight.LEXER_KEYS)))
|
'Invalid lexer "%s" given. Valid lexers are: %s'
|
||||||
|
% (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
|
||||||
# out of it. In case Pygments cannot determine the lexer of the
|
# out of it. In case Pygments cannot determine the lexer of the
|
||||||
|
@ -245,17 +261,16 @@ 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)
|
||||||
else:
|
else:
|
||||||
expires = datetime.datetime.now() + datetime.timedelta(seconds=60 * 60 * 24)
|
expires = datetime.datetime.now() + datetime.timedelta(seconds=60 * 60 * 24)
|
||||||
expire_type = Snippet.EXPIRE_TIME
|
expire_type = Snippet.EXPIRE_TIME
|
||||||
|
|
||||||
snippet = Snippet.objects.create(
|
snippet = Snippet.objects.create(
|
||||||
content=content,
|
content=content, lexer=lexer, expires=expires, expire_type=expire_type
|
||||||
lexer=lexer,
|
|
||||||
expires=expires,
|
|
||||||
expire_type=expire_type,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Custom formatter for the API response
|
# Custom formatter for the API response
|
||||||
|
@ -272,6 +287,7 @@ class APIView(View):
|
||||||
# handle them here.
|
# handle them here.
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
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)
|
return django_page_not_found(request, exception, template_name=template_name)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dpaste.settings.local")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dpaste.settings.local")
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|
Loading…
Reference in a new issue