diff --git a/dpaste/conf.py b/dpaste/conf.py new file mode 100644 index 0000000..b2b99e7 --- /dev/null +++ b/dpaste/conf.py @@ -0,0 +1,38 @@ +"""Default settings for dpaste.""" + +from django.conf import settings +from django.utils.translation import ugettext_lazy as _ + +import appconf +from . import enums + + +class DPasteConf(appconf.AppConf): + class Meta: + prefix = 'dpaste' + + BASE_URL = 'https://dpaste.de' + + # Expiry + EXPIRE_CHOICES = ( + (enums.EXPIRE_ONETIME, _(u'One Time Snippet')), + (enums.EXPIRE_ONE_HOUR, _(u'In one hour')), + (enums.EXPIRE_ONE_WEEK, _(u'In one week')), + (enums.EXPIRE_ONE_MONTH, _(u'In one month')), + # ('never', _(u'Never')), + ) + EXPIRE_DEFAULT = enums.EXPIRE_ONE_MONTH + + # Lexer + LEXER_DEFAULT = 'python' + LEXER_LIST = enums.DEFAULT_LEXER_LIST + LEXER_WORDWRAP = ('text', 'rst') + + # Snippets + SLUG_LENGTH = 4 + SLUG_CHOICES = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890' + MAX_CONTENT_LENGTH = 250 * 1024 * 1024 + + # Users + MAX_SNIPPETS_PER_USER = 15 + ONETIME_LIMIT = 2 diff --git a/dpaste/enums.py b/dpaste/enums.py new file mode 100644 index 0000000..e0cf1ee --- /dev/null +++ b/dpaste/enums.py @@ -0,0 +1,95 @@ +EXPIRE_ONETIME = 'onetime' +EXPIRE_ONE_HOUR = 3600 +EXPIRE_ONE_WEEK = 3600 * 24 * 7 +EXPIRE_ONE_MONTH = 3600 * 24 * 30 + + +# Get a list of all lexer, and then remove all lexer which have '-' or '+' +# or 'with' in the name. Those are too specific and never used. This produces a +# tuple list of [(lexer, Lexer Display Name) ...] lexers. +# >>> from pygments.lexers import get_all_lexers +# >>> ALL_LEXER = set([(i[1][0], i[0]) for i in get_all_lexers()]) +# >>> LEXER_LIST = [l for l in ALL_LEXER if not ( +# >>> '-' in l[0] +# >>> or '+' in l[0] +# >>> or '+' in l[1] +# >>> or 'with' in l[1].lower() +# >>> or ' ' in l[1] +# >>> or l[0] in IGNORE_LEXER +# >>> )] +# >>> LEXER_LIST = sorted(LEXER_LIST) + +# The list of lexers. Its not worth to autogenerate this. See above how to +# retrieve this. +DEFAULT_LEXER_LIST = ( + ('text', 'Text'), + ('text', '----------'), + ('abap', 'ABAP'), + ('apacheconf', 'ApacheConf'), + ('applescript', 'AppleScript'), + ('as', 'ActionScript'), + ('bash', 'Bash'), + ('bbcode', 'BBCode'), + ('c', 'C'), + ('clojure', 'Clojure'), + ('cobol', 'COBOL'), + ('css', 'CSS'), + ('cuda', 'CUDA'), + ('dart', 'Dart'), + ('delphi', 'Delphi'), + ('diff', 'Diff'), + ('django', 'Django'), + ('erlang', 'Erlang'), + ('fortran', 'Fortran'), + ('go', 'Go'), + ('groovy', 'Groovy'), + ('haml', 'Haml'), + ('haskell', 'Haskell'), + ('html', 'HTML'), + ('http', 'HTTP'), + ('ini', 'INI'), + ('irc', 'IRC'), + ('java', 'Java'), + ('js', 'JavaScript'), + ('json', 'JSON'), + ('lua', 'Lua'), + ('make', 'Makefile'), + ('mako', 'Mako'), + ('mason', 'Mason'), + ('matlab', 'Matlab'), + ('modula2', 'Modula'), + ('monkey', 'Monkey'), + ('mysql', 'MySQL'), + ('numpy', 'NumPy'), + ('ocaml', 'OCaml'), + ('perl', 'Perl'), + ('php', 'PHP'), + ('postscript', 'PostScript'), + ('powershell', 'PowerShell'), + ('prolog', 'Prolog'), + ('properties', 'Properties'), + ('puppet', 'Puppet'), + ('python', 'Python'), + ('rb', 'Ruby'), + ('rst', 'reStructuredText'), + ('rust', 'Rust'), + ('sass', 'Sass'), + ('scala', 'Scala'), + ('scheme', 'Scheme'), + ('scilab', 'Scilab'), + ('scss', 'SCSS'), + ('smalltalk', 'Smalltalk'), + ('smarty', 'Smarty'), + ('sql', 'SQL'), + ('tcl', 'Tcl'), + ('tcsh', 'Tcsh'), + ('tex', 'TeX'), + ('text', 'Text'), + ('vb.net', 'VB.net'), + ('vim', 'VimL'), + ('xml', 'XML'), + ('xquery', 'XQuery'), + ('xslt', 'XSLT'), + ('yaml', 'YAML'), +) + diff --git a/dpaste/forms.py b/dpaste/forms.py index c5cc6db..3932cfe 100644 --- a/dpaste/forms.py +++ b/dpaste/forms.py @@ -1,27 +1,18 @@ import datetime from django import forms -from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from dpaste.conf import settings from dpaste.models import Snippet from dpaste.highlight import LEXER_LIST, LEXER_DEFAULT, LEXER_KEYS -EXPIRE_CHOICES = getattr(settings, 'DPASTE_EXPIRE_CHOICES', ( - ('onetime', _(u'One Time Snippet')), - (3600, _(u'In one hour')), - (3600 * 24 * 7, _(u'In one week')), - (3600 * 24 * 30, _(u'In one month')), - # ('never', _(u'Never')), -)) -EXPIRE_DEFAULT = getattr(settings, 'DPASTE_EXPIRE_DEFAULT', EXPIRE_CHOICES[3][0]) -MAX_CONTENT_LENGTH = getattr(settings, 'DPASTE_MAX_CONTENT_LENGTH', 250*1024*1024) class SnippetForm(forms.ModelForm): content = forms.CharField( label=_('Content'), widget=forms.Textarea(attrs={'placeholder': _('Awesome code goes here...')}), - max_length=MAX_CONTENT_LENGTH, + max_length=settings.DPASTE_MAX_CONTENT_LENGTH, ) lexer = forms.ChoiceField( @@ -32,8 +23,8 @@ class SnippetForm(forms.ModelForm): expires = forms.ChoiceField( label=_(u'Expires'), - choices=EXPIRE_CHOICES, - initial=EXPIRE_DEFAULT, + choices=settings.DPASTE_EXPIRE_CHOICES, + initial=settings.DPASTE_EXPIRE_DEFAULT, ) # Honeypot field @@ -91,8 +82,6 @@ class SnippetForm(forms.ModelForm): return expires def save(self, parent=None, *args, **kwargs): - MAX_SNIPPETS_PER_USER = getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 15) - # Set parent snippet if parent: self.instance.parent = parent @@ -111,7 +100,7 @@ class SnippetForm(forms.ModelForm): # Add the snippet to the user session list if self.request.session.get('snippet_list', False): - if len(self.request.session['snippet_list']) >= MAX_SNIPPETS_PER_USER: + if len(self.request.session['snippet_list']) >= settings.DPASTE_MAX_SNIPPETS_PER_USER: self.request.session['snippet_list'].pop(0) self.request.session['snippet_list'] += [self.instance.pk] else: diff --git a/dpaste/highlight.py b/dpaste/highlight.py index 2912b80..396a6fa 100644 --- a/dpaste/highlight.py +++ b/dpaste/highlight.py @@ -1,7 +1,8 @@ from pygments import highlight from pygments.lexers import * from pygments.formatters import HtmlFormatter -from django.conf import settings + +from dpaste.conf import settings """ # Get a list of all lexer, and then remove all lexer which have '-' or '+' @@ -22,85 +23,15 @@ LEXER_LIST = sorted(LEXER_LIST) # The list of lexers. Its not worth to autogenerate this. See above how to # retrieve this. -LEXER_LIST = getattr(settings, 'DPASTE_LEXER_LIST', ( - ('text', 'Text'), - ('text', '----------'), - ('abap', 'ABAP'), - ('apacheconf', 'ApacheConf'), - ('applescript', 'AppleScript'), - ('as', 'ActionScript'), - ('bash', 'Bash'), - ('bbcode', 'BBCode'), - ('c', 'C'), - ('clojure', 'Clojure'), - ('cobol', 'COBOL'), - ('css', 'CSS'), - ('cuda', 'CUDA'), - ('dart', 'Dart'), - ('delphi', 'Delphi'), - ('diff', 'Diff'), - ('django', 'Django'), - ('erlang', 'Erlang'), - ('fortran', 'Fortran'), - ('go', 'Go'), - ('groovy', 'Groovy'), - ('haml', 'Haml'), - ('haskell', 'Haskell'), - ('html', 'HTML'), - ('http', 'HTTP'), - ('ini', 'INI'), - ('irc', 'IRC'), - ('java', 'Java'), - ('js', 'JavaScript'), - ('json', 'JSON'), - ('lua', 'Lua'), - ('make', 'Makefile'), - ('mako', 'Mako'), - ('mason', 'Mason'), - ('matlab', 'Matlab'), - ('modula2', 'Modula'), - ('monkey', 'Monkey'), - ('mysql', 'MySQL'), - ('numpy', 'NumPy'), - ('ocaml', 'OCaml'), - ('perl', 'Perl'), - ('php', 'PHP'), - ('postscript', 'PostScript'), - ('powershell', 'PowerShell'), - ('prolog', 'Prolog'), - ('properties', 'Properties'), - ('puppet', 'Puppet'), - ('python', 'Python'), - ('rb', 'Ruby'), - ('rst', 'reStructuredText'), - ('rust', 'Rust'), - ('sass', 'Sass'), - ('scala', 'Scala'), - ('scheme', 'Scheme'), - ('scilab', 'Scilab'), - ('scss', 'SCSS'), - ('smalltalk', 'Smalltalk'), - ('smarty', 'Smarty'), - ('sql', 'SQL'), - ('tcl', 'Tcl'), - ('tcsh', 'Tcsh'), - ('tex', 'TeX'), - ('text', 'Text'), - ('vb.net', 'VB.net'), - ('vim', 'VimL'), - ('xml', 'XML'), - ('xquery', 'XQuery'), - ('xslt', 'XSLT'), - ('yaml', 'YAML'), -)) +LEXER_LIST = settings.DPASTE_LEXER_LIST LEXER_KEYS = dict(LEXER_LIST).keys() # The default lexer is python -LEXER_DEFAULT = getattr(settings, 'DPASTE_LEXER_DEFAULT', 'python') +LEXER_DEFAULT = settings.DPASTE_LEXER_DEFAULT # Lexers which have wordwrap enabled by default -LEXER_WORDWRAP = getattr(settings, 'DPASTE_LEXER_WORDWRAP', ('text', 'rst')) +LEXER_WORDWRAP = settings.DPASTE_LEXER_WORDWRAP class NakedHtmlFormatter(HtmlFormatter): diff --git a/dpaste/models.py b/dpaste/models.py index 78ea56f..6d0ca5a 100644 --- a/dpaste/models.py +++ b/dpaste/models.py @@ -2,20 +2,15 @@ from random import SystemRandom from django.db import models from django.core.urlresolvers import reverse -from django.conf import settings from django.utils.translation import ugettext_lazy as _ import mptt +from dpaste.conf import settings from dpaste.highlight import LEXER_DEFAULT R = SystemRandom() -L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4) -T = getattr(settings, 'DPASTE_SLUG_CHOICES', - 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890') -ONETIME_LIMIT = getattr(settings, 'DPASTE_ONETIME_LIMIT', 2) - -def generate_secret_id(length=L, alphabet=T): +def generate_secret_id(length=settings.DPASTE_SLUG_LENGTH, alphabet=settings.DPASTE_SLUG_CHOICES): return ''.join([R.choice(alphabet) for i in range(length)]) class Snippet(models.Model): @@ -48,7 +43,7 @@ class Snippet(models.Model): @property def remaining_views(self): if self.expire_type == self.EXPIRE_ONETIME: - remaining = ONETIME_LIMIT - self.view_count + remaining = settings.DPASTE_ONETIME_LIMIT - self.view_count return remaining > 0 and remaining or 0 return None diff --git a/dpaste/tests/test_snippet.py b/dpaste/tests/test_snippet.py index 732ee38..4158cc0 100644 --- a/dpaste/tests/test_snippet.py +++ b/dpaste/tests/test_snippet.py @@ -8,9 +8,9 @@ from django.test.client import Client from django.test import TestCase from django.test.utils import override_settings +from dpaste.conf import settings + from ..models import Snippet -from ..forms import EXPIRE_DEFAULT -from ..highlight import LEXER_DEFAULT class SnippetTestCase(TestCase): @@ -22,8 +22,8 @@ class SnippetTestCase(TestCase): def valid_form_data(self): return { 'content': u"Hello Wörld.\n\tGood Bye", - 'lexer': LEXER_DEFAULT, - 'expires': EXPIRE_DEFAULT, + 'lexer': settings.DPASTE_LEXER_DEFAULT, + 'expires': settings.DPASTE_EXPIRE_DEFAULT, } diff --git a/dpaste/urls/__init__.py b/dpaste/urls/__init__.py index 0a324a4..8188065 100644 --- a/dpaste/urls/__init__.py +++ b/dpaste/urls/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.conf.urls import url, patterns, include urlpatterns = patterns( diff --git a/dpaste/urls/dpaste.py b/dpaste/urls/dpaste.py index 9cac388..337c8c5 100644 --- a/dpaste/urls/dpaste.py +++ b/dpaste/urls/dpaste.py @@ -1,7 +1,10 @@ -from django.conf.urls import url, patterns -from django.conf import settings +from __future__ import absolute_import -L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4) +from django.conf.urls import url, patterns + +from dpaste.conf import settings + +L = settings.DPASTE_SLUG_LENGTH urlpatterns = patterns('dpaste.views', url(r'^about/$', 'about', name='dpaste_about'), diff --git a/dpaste/views.py b/dpaste/views.py index 6e039bf..f669e0a 100644 --- a/dpaste/views.py +++ b/dpaste/views.py @@ -7,7 +7,6 @@ from django.shortcuts import (render_to_response, get_object_or_404) from django.template.context import RequestContext from django.http import (Http404, HttpResponseRedirect, HttpResponseBadRequest, HttpResponse) -from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse @@ -16,8 +15,9 @@ from django.views.defaults import (page_not_found as django_page_not_found, server_error as django_server_error) from django.views.decorators.csrf import csrf_exempt +from dpaste.conf import settings from dpaste.forms import SnippetForm -from dpaste.models import Snippet, ONETIME_LIMIT +from dpaste.models import Snippet from dpaste.highlight import LEXER_WORDWRAP, LEXER_LIST from dpaste.highlight import LEXER_DEFAULT, LEXER_KEYS @@ -60,7 +60,7 @@ def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.h # One time snippet get deleted if the view count matches our limit if snippet.expire_type == Snippet.EXPIRE_ONETIME \ - and snippet.view_count >= ONETIME_LIMIT: + and snippet.view_count >= settings.DPASTE_ONETIME_LIMIT: snippet.delete() raise Http404() @@ -145,7 +145,7 @@ def snippet_history(request, template_name='dpaste/snippet_list.html'): return HttpResponseRedirect(reverse('snippet_history')) template_context = { - 'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10), + 'snippets_max': settings.DPASTE_MAX_SNIPPETS_PER_USER, 'snippet_list': snippet_list, } @@ -259,21 +259,20 @@ def about(request, template_name='dpaste/about.html'): def _format_default(s): """The default response is the snippet URL wrapped in quotes.""" - return u'"%s%s"' % (BASE_URL, s.get_absolute_url()) + return u'"%s%s"' % (settings.DPASTE_BASE_URL, s.get_absolute_url()) def _format_url(s): """The `url` format returns the snippet URL, no quotes, but a linebreak after.""" - return u'%s%s\n' % (BASE_URL, s.get_absolute_url()) + return u'%s%s\n' % (settings.DPASTE_BASE_URL, s.get_absolute_url()) def _format_json(s): """The `json` format export.""" return json.dumps({ - 'url': u'%s%s' % (BASE_URL, s.get_absolute_url()), + 'url': u'%s%s' % (settings.DPASTE_BASE_URL, s.get_absolute_url()), 'content': s.content, 'lexer': s.lexer, }) -BASE_URL = getattr(settings, 'DPASTE_BASE_URL', 'https://dpaste.de') FORMAT_MAPPING = { 'default': _format_default, @@ -297,7 +296,7 @@ def snippet_api(request): s = Snippet.objects.create( content=content, lexer=lexer, - expires=datetime.datetime.now()+datetime.timedelta(seconds=60*60*24*30) + expires=datetime.datetime.now() + datetime.timedelta(seconds=60*60*24*30) ) s.save() diff --git a/requirements.txt b/requirements.txt index c571d69..03e03dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ django==1.6.1 django-mptt==0.6.0 pygments==1.6 requests==2.0.0 +django-appconf==0.6 # Testing python-coveralls==2.4.0