mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 16:12:51 +11:00
Merge branch 'develop'
Conflicts: dpaste/urls/dpaste.py dpaste/views.py
This commit is contained in:
commit
0e251a0392
16 changed files with 255 additions and 637 deletions
|
@ -1,24 +1,23 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from dpaste.models import Snippet
|
from dpaste.models import Snippet
|
||||||
from dpaste.highlight import LEXER_LIST, LEXER_DEFAULT
|
from dpaste.highlight import LEXER_LIST, LEXER_DEFAULT
|
||||||
import datetime
|
|
||||||
|
|
||||||
#===============================================================================
|
|
||||||
# Snippet Form and Handling
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
EXPIRE_CHOICES = (
|
EXPIRE_CHOICES = (
|
||||||
(3600, _(u'In one hour')),
|
(3600, _(u'In one hour')),
|
||||||
(3600 * 24 * 7, _(u'In one week')),
|
(3600 * 24 * 7, _(u'In one week')),
|
||||||
(3600 * 24 * 30, _(u'In one month')),
|
(3600 * 24 * 30, _(u'In one month')),
|
||||||
)
|
)
|
||||||
|
EXPIRE_DEFAULT = EXPIRE_CHOICES[2][0]
|
||||||
EXPIRE_DEFAULT = 3600 * 24 * 30
|
|
||||||
|
|
||||||
MAX_CONTENT_LENGTH = getattr(settings, 'DPASTE_MAX_CONTENT_LENGTH', 250*1024*1024)
|
MAX_CONTENT_LENGTH = getattr(settings, 'DPASTE_MAX_CONTENT_LENGTH', 250*1024*1024)
|
||||||
|
MAX_SNIPPETS_PER_USER = getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 15)
|
||||||
|
|
||||||
|
\
|
||||||
class SnippetForm(forms.ModelForm):
|
class SnippetForm(forms.ModelForm):
|
||||||
content = forms.CharField(
|
content = forms.CharField(
|
||||||
label=_('Content'),
|
label=_('Content'),
|
||||||
|
@ -29,7 +28,7 @@ class SnippetForm(forms.ModelForm):
|
||||||
lexer = forms.ChoiceField(
|
lexer = forms.ChoiceField(
|
||||||
label=_(u'Lexer'),
|
label=_(u'Lexer'),
|
||||||
initial=LEXER_DEFAULT,
|
initial=LEXER_DEFAULT,
|
||||||
widget=forms.TextInput,
|
choices=LEXER_LIST,
|
||||||
)
|
)
|
||||||
|
|
||||||
expire_options = forms.ChoiceField(
|
expire_options = forms.ChoiceField(
|
||||||
|
@ -55,35 +54,23 @@ class SnippetForm(forms.ModelForm):
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(SnippetForm, self).__init__(*args, **kwargs)
|
super(SnippetForm, self).__init__(*args, **kwargs)
|
||||||
self.request = request
|
self.request = request
|
||||||
self.fields['lexer'].choices = LEXER_LIST
|
|
||||||
self.fields['lexer'].widget.attrs = {
|
|
||||||
'autocomplete': 'off',
|
|
||||||
'data-provide': 'typeahead',
|
|
||||||
'data-source': '["%s"]' % '","'.join(dict(LEXER_LIST).keys())
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set the recently used lexer if we have any
|
# Set the recently used lexer if we have any
|
||||||
session_lexer = self.request.session.get('lexer')
|
session_lexer = self.request.session.get('lexer')
|
||||||
if session_lexer and session_lexer in dict(LEXER_LIST).keys():
|
if session_lexer and session_lexer in dict(LEXER_LIST).keys():
|
||||||
self.fields['lexer'].initial = session_lexer
|
self.fields['lexer'].initial = session_lexer
|
||||||
|
|
||||||
def clean_lexer(self):
|
|
||||||
lexer = self.cleaned_data.get('lexer')
|
|
||||||
if not lexer:
|
|
||||||
return LEXER_DEFAULT
|
|
||||||
lexer = dict(LEXER_LIST).get(lexer, LEXER_DEFAULT)
|
|
||||||
return lexer
|
|
||||||
|
|
||||||
def clean_content(self):
|
def clean_content(self):
|
||||||
return self.cleaned_data.get('content', '').strip()
|
return self.cleaned_data.get('content', '').strip()
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
# The `title` field is a hidden honeypot field. If its filled,
|
||||||
|
# this is likely spam.
|
||||||
if self.cleaned_data.get('title'):
|
if self.cleaned_data.get('title'):
|
||||||
raise forms.ValidationError('This snippet was identified as Spam.')
|
raise forms.ValidationError('This snippet was identified as Spam.')
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
def save(self, parent=None, *args, **kwargs):
|
def save(self, parent=None, *args, **kwargs):
|
||||||
|
|
||||||
# Set parent snippet
|
# Set parent snippet
|
||||||
if parent:
|
if parent:
|
||||||
self.instance.parent = parent
|
self.instance.parent = parent
|
||||||
|
@ -97,7 +84,7 @@ class SnippetForm(forms.ModelForm):
|
||||||
|
|
||||||
# Add the snippet to the user session list
|
# Add the snippet to the user session list
|
||||||
if self.request.session.get('snippet_list', False):
|
if self.request.session.get('snippet_list', False):
|
||||||
if len(self.request.session['snippet_list']) >= getattr(settings, 'MAX_SNIPPETS_PER_USER', 10):
|
if len(self.request.session['snippet_list']) >= MAX_SNIPPETS_PER_USER:
|
||||||
self.request.session['snippet_list'].pop(0)
|
self.request.session['snippet_list'].pop(0)
|
||||||
self.request.session['snippet_list'] += [self.instance.pk]
|
self.request.session['snippet_list'] += [self.instance.pk]
|
||||||
else:
|
else:
|
||||||
|
@ -106,4 +93,4 @@ class SnippetForm(forms.ModelForm):
|
||||||
# Save the lexer in the session so we can use it later again
|
# Save the lexer in the session so we can use it later again
|
||||||
self.request.session['lexer'] = self.cleaned_data['lexer']
|
self.request.session['lexer'] = self.cleaned_data['lexer']
|
||||||
|
|
||||||
return self.request, self.instance
|
return self.instance
|
|
@ -1,23 +1,102 @@
|
||||||
from pygments import highlight
|
from pygments import highlight
|
||||||
from pygments.lexers import *
|
from pygments.lexers import *
|
||||||
from pygments.lexers import get_all_lexers
|
|
||||||
from pygments.formatters import HtmlFormatter
|
from pygments.formatters import HtmlFormatter
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from django.utils.html import escape
|
"""
|
||||||
|
# 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)
|
||||||
|
"""
|
||||||
|
|
||||||
import logging
|
# The list of lexers. Its not worth to autogenerate this. See above how to
|
||||||
logger = logging.getLogger(__name__)
|
# retrieve this.
|
||||||
|
LEXER_LIST = getattr(settings, 'DPASTE_LEXER_LIST', (
|
||||||
|
('text', 'Text'),
|
||||||
|
('text', '----------'),
|
||||||
|
('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'),
|
||||||
|
('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'),
|
||||||
|
('vb.net', 'VB.net'),
|
||||||
|
('vim', 'VimL'),
|
||||||
|
('xml', 'XML'),
|
||||||
|
('xquery', 'XQuery'),
|
||||||
|
('xslt', 'XSLT'),
|
||||||
|
('yaml', 'YAML'),
|
||||||
|
))
|
||||||
|
|
||||||
# Python 3: python3
|
# The default lexer is python
|
||||||
LEXER_LIST = sorted([(i[0], i[0]) for i in get_all_lexers() if not (
|
LEXER_DEFAULT = getattr(settings, 'DPASTE_LEXER_DEFAULT', 'python')
|
||||||
'+' in i[0] or
|
|
||||||
'with' in i[0].lower() or
|
# Lexers which have wordwrap enabled by default
|
||||||
i[0].islower()
|
LEXER_WORDWRAP = getattr(settings, 'DPASTE_LEXER_WORDWRAP', ('text', 'rst'))
|
||||||
)])
|
|
||||||
LEXER_LIST_NAME = dict([(i[0], i[1][0]) for i in get_all_lexers()])
|
|
||||||
|
|
||||||
LEXER_DEFAULT = 'Python'
|
|
||||||
LEXER_WORDWRAP = ('text', 'rst')
|
|
||||||
|
|
||||||
class NakedHtmlFormatter(HtmlFormatter):
|
class NakedHtmlFormatter(HtmlFormatter):
|
||||||
def wrap(self, source, outfile):
|
def wrap(self, source, outfile):
|
||||||
|
@ -28,25 +107,6 @@ class NakedHtmlFormatter(HtmlFormatter):
|
||||||
yield i, t
|
yield i, t
|
||||||
|
|
||||||
def pygmentize(code_string, lexer_name=LEXER_DEFAULT):
|
def pygmentize(code_string, lexer_name=LEXER_DEFAULT):
|
||||||
lexer_name = LEXER_LIST_NAME.get(lexer_name, None)
|
lexer = lexer_name and get_lexer_by_name(lexer_name) \
|
||||||
try:
|
or PythonLexer()
|
||||||
if lexer_name:
|
return highlight(code_string, lexer, NakedHtmlFormatter())
|
||||||
lexer = get_lexer_by_name(lexer_name)
|
|
||||||
else:
|
|
||||||
raise Exception
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
lexer = guess_lexer(code_string)
|
|
||||||
except:
|
|
||||||
lexer = PythonLexer()
|
|
||||||
|
|
||||||
try:
|
|
||||||
return highlight(code_string, lexer, NakedHtmlFormatter())
|
|
||||||
except:
|
|
||||||
return escape(code_string)
|
|
||||||
|
|
||||||
def guess_code_lexer(code_string, default_lexer='unknown'):
|
|
||||||
try:
|
|
||||||
return guess_lexer(code_string).name
|
|
||||||
except ValueError:
|
|
||||||
return default_lexer
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
# Deleting field 'Snippet.content_highlighted'
|
||||||
|
db.delete_column(u'dpaste_snippet', 'content_highlighted')
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Adding field 'Snippet.content_highlighted'
|
||||||
|
db.add_column(u'dpaste_snippet', 'content_highlighted',
|
||||||
|
self.gf('django.db.models.fields.TextField')(default='', blank=True),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
u'dpaste.snippet': {
|
||||||
|
'Meta': {'ordering': "('-published',)", 'object_name': 'Snippet'},
|
||||||
|
'content': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'expires': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||||
|
'lexer': ('django.db.models.fields.CharField', [], {'default': "'Python'", 'max_length': '30'}),
|
||||||
|
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||||
|
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['dpaste.Snippet']"}),
|
||||||
|
'published': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
|
||||||
|
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||||
|
'secret_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||||
|
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['dpaste']
|
|
@ -7,16 +7,15 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from dpaste.highlight import LEXER_DEFAULT
|
from dpaste.highlight import LEXER_DEFAULT
|
||||||
|
|
||||||
t = 'abcdefghijkmnopqrstuvwwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ1234567890'
|
t = 'abcdefghijkmnopqrstuvwwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ1234567890'
|
||||||
def generate_secret_id(length=5):
|
def generate_secret_id(length=4):
|
||||||
return ''.join([random.choice(t) for i in range(length)])
|
return ''.join([random.choice(t) for i in range(length)])
|
||||||
|
|
||||||
class Snippet(models.Model):
|
class Snippet(models.Model):
|
||||||
secret_id = models.CharField(_(u'Secret ID'), max_length=255, blank=True)
|
secret_id = models.CharField(_(u'Secret ID'), max_length=255, blank=True)
|
||||||
content = models.TextField(_(u'Content'), )
|
content = models.TextField(_(u'Content'), )
|
||||||
content_highlighted = models.TextField(_(u'Highlighted Content'), blank=True)
|
|
||||||
lexer = models.CharField(_(u'Lexer'), max_length=30, default=LEXER_DEFAULT)
|
lexer = models.CharField(_(u'Lexer'), max_length=30, default=LEXER_DEFAULT)
|
||||||
published = models.DateTimeField(_(u'Published'), blank=True)
|
published = models.DateTimeField(_(u'Published'), blank=True)
|
||||||
expires = models.DateTimeField(_(u'Expires'), blank=True, help_text='asdf')
|
expires = models.DateTimeField(_(u'Expires'), blank=True)
|
||||||
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
|
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -27,7 +26,7 @@ class Snippet(models.Model):
|
||||||
return len(self.content.splitlines())
|
return len(self.content.splitlines())
|
||||||
|
|
||||||
def content_splitted(self):
|
def content_splitted(self):
|
||||||
return self.content_highlighted.splitlines()
|
return self.content.splitlines()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_single(self):
|
def is_single(self):
|
||||||
|
@ -37,13 +36,12 @@ class Snippet(models.Model):
|
||||||
if not self.pk:
|
if not self.pk:
|
||||||
self.published = datetime.datetime.now()
|
self.published = datetime.datetime.now()
|
||||||
self.secret_id = generate_secret_id()
|
self.secret_id = generate_secret_id()
|
||||||
self.content_highlighted = self.content
|
|
||||||
super(Snippet, self).save(*args, **kwargs)
|
super(Snippet, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('snippet_details', kwargs={'snippet_id': self.secret_id})
|
return reverse('snippet_details', kwargs={'snippet_id': self.secret_id})
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '%s' % self.secret_id
|
return self.secret_id
|
||||||
|
|
||||||
mptt.register(Snippet, order_insertion_by=['content'])
|
mptt.register(Snippet, order_insertion_by=['content'])
|
|
@ -19,4 +19,4 @@ DATABASES = {
|
||||||
|
|
||||||
SECRET_KEY = 'changeme'
|
SECRET_KEY = 'changeme'
|
||||||
|
|
||||||
EMAIL_BACKEND = 'dpaste.smtp.EmailBackend'
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
"""sendmail email backend class."""
|
|
||||||
|
|
||||||
import threading
|
|
||||||
|
|
||||||
from django.core.mail.backends.base import BaseEmailBackend
|
|
||||||
from subprocess import Popen, PIPE
|
|
||||||
|
|
||||||
|
|
||||||
class EmailBackend(BaseEmailBackend):
|
|
||||||
"""
|
|
||||||
EmailBackend that uses a local 'sendmail' binary instead of a local
|
|
||||||
SMTP daemon.
|
|
||||||
"""
|
|
||||||
def __init__(self, fail_silently=False, **kwargs):
|
|
||||||
super(EmailBackend, self).__init__(fail_silently=fail_silently)
|
|
||||||
self._lock = threading.RLock()
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def send_messages(self, email_messages):
|
|
||||||
"""
|
|
||||||
Sends one or more EmailMessage objects and returns the number of email
|
|
||||||
messages sent.
|
|
||||||
"""
|
|
||||||
if not email_messages:
|
|
||||||
return
|
|
||||||
self._lock.acquire()
|
|
||||||
try:
|
|
||||||
num_sent = 0
|
|
||||||
for message in email_messages:
|
|
||||||
sent = self._send(message)
|
|
||||||
if sent:
|
|
||||||
num_sent += 1
|
|
||||||
finally:
|
|
||||||
self._lock.release()
|
|
||||||
return num_sent
|
|
||||||
|
|
||||||
def _send(self, email_message):
|
|
||||||
"""A helper method that does the actual sending."""
|
|
||||||
if not email_message.recipients():
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
ps = Popen(["sendmail"]+list(email_message.recipients()), \
|
|
||||||
stdin=PIPE)
|
|
||||||
ps.stdin.write(email_message.message().as_string())
|
|
||||||
ps.stdin.flush()
|
|
||||||
ps.stdin.close()
|
|
||||||
return not ps.wait()
|
|
||||||
except:
|
|
||||||
if not self.fail_silently:
|
|
||||||
raise
|
|
||||||
return False
|
|
||||||
return True
|
|
|
@ -1,404 +0,0 @@
|
||||||
body{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link,
|
|
||||||
a:visited{
|
|
||||||
color: #3D813A;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover{
|
|
||||||
color: #52AA4D;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.hint{
|
|
||||||
color: #333;
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.hint em{
|
|
||||||
color: black;
|
|
||||||
background-color: #c9f8b4;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 2px 3px;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr.clear{
|
|
||||||
clear: both;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: 0;
|
|
||||||
line-height: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.success{
|
|
||||||
background-color: green;
|
|
||||||
color: White;
|
|
||||||
margin: 10px 0;
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.success a{
|
|
||||||
color: White;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.hint{
|
|
||||||
padding: 5px 20px;
|
|
||||||
background-color: #F7F1C9;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* *******************************************
|
|
||||||
* Header
|
|
||||||
******************************************* */
|
|
||||||
|
|
||||||
#header{
|
|
||||||
background-color: #D6F1B7;
|
|
||||||
border-bottom: 1px solid #C6EB9A;
|
|
||||||
padding: 10px 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header span.new_snippet{
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header h1{
|
|
||||||
margin: 0;
|
|
||||||
color: #555555;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header h1 span.date{
|
|
||||||
color: gray;
|
|
||||||
color: #666;
|
|
||||||
padding-left: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header a:link,
|
|
||||||
#header a:visited{
|
|
||||||
text-decoration: none;
|
|
||||||
color: #333;
|
|
||||||
font-weight: Bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header a:hover{
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *******************************************
|
|
||||||
* Content
|
|
||||||
******************************************* */
|
|
||||||
|
|
||||||
#content{
|
|
||||||
padding: 0 20px;
|
|
||||||
margin: 0;
|
|
||||||
width: 70%;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#content h2{
|
|
||||||
font-size: 1.3em;
|
|
||||||
line-height: 1.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content h2.divider{
|
|
||||||
font-size: 1em;
|
|
||||||
padding: 5px 20px;
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
margin: 40px 0 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content h2 span{
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.accordion h2{
|
|
||||||
cursor: pointer;
|
|
||||||
color: #3D813A;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.accordion h2:hover{
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *******************************************
|
|
||||||
* Snippet table
|
|
||||||
******************************************* */
|
|
||||||
div.snippet{
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.snippet-options{
|
|
||||||
float: right;
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.snippet table{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.snippet table td{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 4px;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.snippet table th{
|
|
||||||
border-right: 1px solid #ccc;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.snippet table th a{
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #888;
|
|
||||||
text-align: right;
|
|
||||||
padding: 0 4px 0 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *******************************************
|
|
||||||
* Form
|
|
||||||
******************************************* */
|
|
||||||
form.snippetform ol{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform ol li{
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-bottom: 1px solid #EEE;
|
|
||||||
clear: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform label{
|
|
||||||
width: 125px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform #id_content{
|
|
||||||
width: 80%;
|
|
||||||
height: 320px;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform #id_author,
|
|
||||||
form.snippetform #id_title{
|
|
||||||
width: 60%;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform li.submit input{
|
|
||||||
margin-left: 125px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform ul.errorlist,
|
|
||||||
form.snippetform ul.errorlist li{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
color: #c00;
|
|
||||||
font-weight: bold;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.snippetform ul.errorlist li{
|
|
||||||
padding: 10px 0 5px 0;
|
|
||||||
}
|
|
||||||
/* *******************************************
|
|
||||||
* History + Tree
|
|
||||||
******************************************* */
|
|
||||||
|
|
||||||
#sidebar{
|
|
||||||
padding: 0 20px 0 10px;
|
|
||||||
margin: 20px 0 0 0;
|
|
||||||
float: right;
|
|
||||||
width: 20%;
|
|
||||||
overflow: auto;
|
|
||||||
border-left: 1px solid #DDD;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar h2{
|
|
||||||
font-size: 1em;
|
|
||||||
border-bottom: 1px solid #DDD;
|
|
||||||
color: #888;
|
|
||||||
margin-top: 0;
|
|
||||||
text-transform: uppercase;
|
|
||||||
width: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree{
|
|
||||||
margin: 0 0 15px 0;
|
|
||||||
line-height: 1.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree ul,
|
|
||||||
div.tree ul li{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree ul li{
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree ul li div{
|
|
||||||
border-bottom: 1px solid #EEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree span.diff{
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree strong{
|
|
||||||
color: #111;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree ul li li{
|
|
||||||
padding-left: 0;
|
|
||||||
margin-left: 15px;
|
|
||||||
color: #ccc;
|
|
||||||
list-style: circle;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree div.submit{
|
|
||||||
margin: 8px 0 0 0;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.tree div.submit input{
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *******************************************
|
|
||||||
* Footer
|
|
||||||
******************************************* */
|
|
||||||
|
|
||||||
#footer{
|
|
||||||
position: fixed;
|
|
||||||
right: 1em;
|
|
||||||
bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer form.setlang{
|
|
||||||
display: inline;
|
|
||||||
padding-right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer form.setlang input,
|
|
||||||
#footer form.setlang select{
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer a:link,
|
|
||||||
#footer a:visited{
|
|
||||||
background-color: #D6F1B7;
|
|
||||||
color: #555;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 3px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer a:hover,
|
|
||||||
#footer a:active{
|
|
||||||
background-color: #D6F1B7;
|
|
||||||
color: #000;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *******************************************
|
|
||||||
* Pygments
|
|
||||||
******************************************* */
|
|
||||||
|
|
||||||
pre.code {
|
|
||||||
font-family: "Bitstream Vera Sans Mono", Monaco, Consolas, monospace;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 17px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.code div.line:hover{
|
|
||||||
background-color: #FFFFE6;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.code div.line.marked,
|
|
||||||
pre.code div.line.marked *{
|
|
||||||
background-color: #BAE688 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code .c { color: #999988; font-style: italic } /* Comment */
|
|
||||||
/* .code .err { color: #a61717; background-color: #e3d2d2 } /* Error */
|
|
||||||
.code .k { font-weight: bold } /* Keyword */
|
|
||||||
.code .o { font-weight: bold } /* Operator */
|
|
||||||
.code .cm { color: #999988; font-style: italic } /* Comment.Multiline */
|
|
||||||
.code .cp { color: #999999; font-weight: bold } /* Comment..codeproc */
|
|
||||||
.code .c1 { color: #999988; font-style: italic } /* Comment.Single */
|
|
||||||
.code .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
|
|
||||||
.code .ge { font-style: italic } /* Generic.Emph */
|
|
||||||
.code .gr { color: #aa0000 } /* Generic.Error */
|
|
||||||
.code .gh { color: #999999 } /* Generic.Heading */
|
|
||||||
.code .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
|
|
||||||
.code .go { color: #888888 } /* Generic.Output */
|
|
||||||
.code .gp { color: #555555 } /* Generic.Prompt */
|
|
||||||
.code .gs { font-weight: bold } /* Generic.Strong */
|
|
||||||
.code .gu { color: #aaaaaa } /* Generic.Subheading */
|
|
||||||
.code .gt { color: #aa0000 } /* Generic.Traceback */
|
|
||||||
.code .kc { font-weight: bold } /* Keyword.Constant */
|
|
||||||
.code .kd { font-weight: bold } /* Keyword.Declaration */
|
|
||||||
.code .kp { font-weight: bold } /* Keyword.Pseudo */
|
|
||||||
.code .kr { font-weight: bold } /* Keyword.Reserved */
|
|
||||||
.code .kt { color: #445588; font-weight: bold } /* Keyword.Type */
|
|
||||||
.code .m { color: #009999 } /* Literal.Number */
|
|
||||||
.code .s { color: #bb8844 } /* Literal.String */
|
|
||||||
.code .na { color: #008080 } /* Name.Attribute */
|
|
||||||
.code .nb { color: #999999 } /* Name.Builtin */
|
|
||||||
.code .nc { color: #445588; font-weight: bold } /* Name.Class */
|
|
||||||
.code .no { color: #ff99ff } /* Name.Constant */
|
|
||||||
.code .ni { color: #800080 } /* Name.Entity */
|
|
||||||
.code .ne { color: #990000; font-weight: bold } /* Name.Exception */
|
|
||||||
.code .nf { color: #990000; font-weight: bold } /* Name.Function */
|
|
||||||
.code .nn { color: #555555 } /* Name.Namespace */
|
|
||||||
.code .nt { color: #000080 } /* Name.Tag */
|
|
||||||
.code .nv { color: purple } /* Name.Variable */
|
|
||||||
.code .ow { font-weight: bold } /* Operator.Word */
|
|
||||||
.code .mf { color: #009999 } /* Literal.Number.Float */
|
|
||||||
.code .mh { color: #009999 } /* Literal.Number.Hex */
|
|
||||||
.code .mi { color: #009999 } /* Literal.Number.Integer */
|
|
||||||
.code .mo { color: #009999 } /* Literal.Number.Oct */
|
|
||||||
.code .sb { color: #bb8844 } /* Literal.String.Backtick */
|
|
||||||
.code .sc { color: #bb8844 } /* Literal.String.Char */
|
|
||||||
.code .sd { color: #bb8844 } /* Literal.String.Doc */
|
|
||||||
.code .s2 { color: #bb8844 } /* Literal.String.Double */
|
|
||||||
.code .se { color: #bb8844 } /* Literal.String.Escape */
|
|
||||||
.code .sh { color: #bb8844 } /* Literal.String.Heredoc */
|
|
||||||
.code .si { color: #bb8844 } /* Literal.String.Interpol */
|
|
||||||
.code .sx { color: #bb8844 } /* Literal.String.Other */
|
|
||||||
.code .sr { color: #808000 } /* Literal.String.Regex */
|
|
||||||
.code .s1 { color: #bb8844 } /* Literal.String.Single */
|
|
||||||
.code .ss { color: #bb8844 } /* Literal.String.Symbol */
|
|
||||||
.code .bp { color: #999999 } /* Name.Builtin.Pseudo */
|
|
||||||
.code .vc { color: #ff99ff } /* Name.Variable.Class */
|
|
||||||
.code .vg { color: #ff99ff } /* Name.Variable.Global */
|
|
||||||
.code .vi { color: #ff99ff } /* Name.Variable.Instance */
|
|
||||||
.code .il { color: #009999 } /* Literal.Number.Integer.Long */
|
|
7
dpaste/static/dpaste/typeahead.min.js
vendored
Normal file
7
dpaste/static/dpaste/typeahead.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -28,33 +28,6 @@
|
||||||
|
|
||||||
{% block script_footer %}
|
{% block script_footer %}
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
|
||||||
<script src="{% static "dpaste/bootstrap/js/bootstrap.min.js" %}"></script>
|
|
||||||
<script>
|
|
||||||
jQuery(function($) {
|
|
||||||
var lexerReq;
|
|
||||||
$('#guess_lexer_btn').click(function() {
|
|
||||||
// Cancel previous request if it is still pending
|
|
||||||
if (lexerReq) {
|
|
||||||
lexerReq.abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
lexerReq = $.getJSON('{% url "snippet_guess_lexer" %}', {
|
|
||||||
codestring: $('#id_content').val()
|
|
||||||
}).done(function(data) {
|
|
||||||
if (data.lexer === 'unknown') {
|
|
||||||
$('#guess_lexer_btn').css('color', 'red');
|
|
||||||
} else {
|
|
||||||
$('#id_lexer').val(data.lexer);
|
|
||||||
$('#guess_lexer_btn').css('color', 'inherit');
|
|
||||||
}
|
|
||||||
}).complete(function() {
|
|
||||||
lexerReq = null;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.autofocus input:text, .autofocus textarea').first().focus();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -81,15 +81,15 @@
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script>
|
<script>
|
||||||
jQuery(function($) {
|
jQuery(function($) {
|
||||||
var diffReq;
|
|
||||||
|
|
||||||
$('.snippet-reply-hidden').click(function(e) {
|
$('.snippet-reply-hidden').click(function(e) {
|
||||||
$(this).removeClass('snippet-reply-hidden');
|
$(this).removeClass('snippet-reply-hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/* ------------------------------------------------------------------------
|
||||||
* Diff Ajax Call
|
Diff Ajax Call
|
||||||
*/
|
------------------------------------------------------------------------ */
|
||||||
|
var diffReq;
|
||||||
|
|
||||||
$('.snippet-diff-trigger').click(function(e) {
|
$('.snippet-diff-trigger').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$('#snippet-diff').slideDown('fast');
|
$('#snippet-diff').slideDown('fast');
|
||||||
|
@ -134,10 +134,9 @@ jQuery(function($) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* ------------------------------------------------------------------------
|
||||||
* Line Highlighting
|
Line Highlighting
|
||||||
*/
|
------------------------------------------------------------------------ */
|
||||||
|
|
||||||
if (curLine.substring(0, 2) === '#L') {
|
if (curLine.substring(0, 2) === '#L') {
|
||||||
hashlist = curLine.substring(2).split(',');
|
hashlist = curLine.substring(2).split(',');
|
||||||
if (hashlist.length > 0 && hashlist[0] !== '') {
|
if (hashlist.length > 0 && hashlist[0] !== '') {
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
{% if snippet_form.lexer.errors %}control-group error{% endif %}">
|
{% if snippet_form.lexer.errors %}control-group error{% endif %}">
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
{{ snippet_form.lexer }}
|
{{ snippet_form.lexer }}
|
||||||
<button class="btn" id="guess_lexer_btn" type="button">{% trans "Guess lexer" %}</button>
|
|
||||||
</div>
|
</div>
|
||||||
{% for error in snippet_form.lexer.errors %}
|
{% for error in snippet_form.lexer.errors %}
|
||||||
<span class="help-inline">{{ error }}</span>
|
<span class="help-inline">{{ error }}</span>
|
||||||
|
@ -42,4 +41,4 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<input tabindex="0" type="submit"class="btn btn-primary" value="{% trans "Paste it" %}">
|
<input tabindex="0" type="submit"class="btn btn-primary" value="{% trans "Paste it" %}">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "dpaste/base.html" %}
|
{% extends "dpaste/base.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load dpaste_tags %}
|
{% load dpaste_tags %}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,6 @@ class SnippetAPITestCase(TestCase):
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
"""
|
"""
|
||||||
The browser sent a content field but with no data.
|
The browser sent a content field but with no data.
|
||||||
|
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
|
|
||||||
ALL tests fail due to a Piston bug:
|
|
||||||
https://bitbucket.org/jespern/django-piston/issue/221/attributeerror-httpresponseservererror
|
|
||||||
"""
|
"""
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ from django.conf.urls.defaults import url, patterns
|
||||||
|
|
||||||
urlpatterns = patterns('dpaste.views',
|
urlpatterns = patterns('dpaste.views',
|
||||||
url(r'^$', 'snippet_new', name='snippet_new'),
|
url(r'^$', 'snippet_new', name='snippet_new'),
|
||||||
url(r'^guess/$', 'guess_lexer', name='snippet_guess_lexer'),
|
|
||||||
url(r'^diff/$', 'snippet_diff', name='snippet_diff'),
|
url(r'^diff/$', 'snippet_diff', name='snippet_diff'),
|
||||||
url(r'^history/$', 'snippet_history', name='snippet_history'),
|
url(r'^history/$', 'snippet_history', name='snippet_history'),
|
||||||
url(r'^delete/$', 'snippet_delete', name='snippet_delete'),
|
url(r'^delete/$', 'snippet_delete', name='snippet_delete'),
|
||||||
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/$', 'snippet_details', name='snippet_details'),
|
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/$', 'snippet_details', name='snippet_details'),
|
||||||
|
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/?$', 'snippet_details', name='snippet_details'),
|
||||||
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/delete/$', 'snippet_delete', name='snippet_delete'),
|
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/delete/$', 'snippet_delete', name='snippet_delete'),
|
||||||
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/gist/$', 'snippet_gist', name='snippet_gist'),
|
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/gist/$', 'snippet_gist', name='snippet_gist'),
|
||||||
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/raw/$', 'snippet_details', {'template_name': 'dpaste/snippet_details_raw.html', 'is_raw': True}, name='snippet_details_raw'),
|
url(r'^(?P<snippet_id>[a-zA-Z0-9]+)/raw/$', 'snippet_details', {'template_name': 'dpaste/snippet_details_raw.html', 'is_raw': True}, name='snippet_details_raw'),
|
||||||
|
|
143
dpaste/views.py
143
dpaste/views.py
|
@ -2,45 +2,36 @@ import datetime
|
||||||
import difflib
|
import difflib
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
|
from django.shortcuts import (render_to_response, get_object_or_404,
|
||||||
|
get_list_or_404)
|
||||||
from django.template.context import RequestContext
|
from django.template.context import RequestContext
|
||||||
from django.http import (Http404, HttpResponseRedirect, HttpResponseBadRequest,
|
from django.http import (Http404, HttpResponseRedirect, HttpResponseBadRequest,
|
||||||
HttpResponse, HttpResponseForbidden)
|
HttpResponse, HttpResponseForbidden)
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils import simplejson
|
from django.utils import simplejson
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.views.defaults import (page_not_found as django_page_not_found,
|
from django.views.defaults import (page_not_found as django_page_not_found,
|
||||||
server_error as django_server_error)
|
server_error as django_server_error)
|
||||||
|
|
||||||
from dpaste.forms import SnippetForm
|
from dpaste.forms import SnippetForm
|
||||||
from dpaste.models import Snippet
|
from dpaste.models import Snippet
|
||||||
from dpaste.highlight import guess_code_lexer, \
|
from dpaste.highlight import LEXER_WORDWRAP, LEXER_LIST
|
||||||
LEXER_WORDWRAP, LEXER_LIST
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Snippet Handling
|
||||||
def about(request, template_name='dpaste/about.html'):
|
# -----------------------------------------------------------------------------
|
||||||
template_context = {
|
|
||||||
'total': Snippet.objects.count(),
|
|
||||||
'stats': Snippet.objects.values('lexer').annotate(
|
|
||||||
count=Count('lexer')).order_by('-count')[:5],
|
|
||||||
}
|
|
||||||
|
|
||||||
return render_to_response(
|
|
||||||
template_name,
|
|
||||||
template_context,
|
|
||||||
RequestContext(request)
|
|
||||||
)
|
|
||||||
|
|
||||||
def snippet_new(request, template_name='dpaste/snippet_new.html'):
|
def snippet_new(request, template_name='dpaste/snippet_new.html'):
|
||||||
|
"""
|
||||||
|
Create a new snippet.
|
||||||
|
"""
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
snippet_form = SnippetForm(data=request.POST, request=request)
|
snippet_form = SnippetForm(data=request.POST, request=request)
|
||||||
if snippet_form.is_valid():
|
if snippet_form.is_valid():
|
||||||
request, new_snippet = snippet_form.save()
|
new_snippet = snippet_form.save()
|
||||||
url = new_snippet.get_absolute_url()
|
url = new_snippet.get_absolute_url()
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
|
@ -48,6 +39,7 @@ def snippet_new(request, template_name='dpaste/snippet_new.html'):
|
||||||
|
|
||||||
template_context = {
|
template_context = {
|
||||||
'snippet_form': snippet_form,
|
'snippet_form': snippet_form,
|
||||||
|
'lexer_list': LEXER_LIST,
|
||||||
'is_new': True,
|
'is_new': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,25 +50,11 @@ def snippet_new(request, template_name='dpaste/snippet_new.html'):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def snippet_api(request, enclose_quotes=True):
|
|
||||||
content = request.POST.get('content', '').strip()
|
|
||||||
|
|
||||||
if not content:
|
|
||||||
return HttpResponseBadRequest()
|
|
||||||
|
|
||||||
s = Snippet.objects.create(
|
|
||||||
content=content,
|
|
||||||
expires=datetime.datetime.now()+datetime.timedelta(seconds=60*60*24*30)
|
|
||||||
)
|
|
||||||
s.save()
|
|
||||||
|
|
||||||
response = 'http://dpaste.de%s' % s.get_absolute_url()
|
|
||||||
if enclose_quotes:
|
|
||||||
return HttpResponse('"%s"' % response)
|
|
||||||
return HttpResponse(response)
|
|
||||||
|
|
||||||
def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.html', is_raw=False):
|
def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.html', is_raw=False):
|
||||||
|
"""
|
||||||
|
Details list view of a snippet. Handles the actual view, reply and
|
||||||
|
tree/diff view.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
snippet = Snippet.objects.get(secret_id=snippet_id)
|
snippet = Snippet.objects.get(secret_id=snippet_id)
|
||||||
except MultipleObjectsReturned:
|
except MultipleObjectsReturned:
|
||||||
|
@ -98,7 +76,7 @@ def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.h
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
snippet_form = SnippetForm(data=request.POST, request=request, initial=new_snippet_initial)
|
snippet_form = SnippetForm(data=request.POST, request=request, initial=new_snippet_initial)
|
||||||
if snippet_form.is_valid():
|
if snippet_form.is_valid():
|
||||||
request, new_snippet = snippet_form.save(parent=snippet)
|
new_snippet = snippet_form.save(parent=snippet)
|
||||||
url = new_snippet.get_absolute_url()
|
url = new_snippet.get_absolute_url()
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
|
@ -125,34 +103,31 @@ def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.h
|
||||||
else:
|
else:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def snippet_delete(request, snippet_id=None):
|
|
||||||
snippet_id = snippet_id or request.POST.get('snippet_id')
|
|
||||||
if not snippet_id:
|
|
||||||
return HttpResponseBadRequest('No snippet given!')
|
|
||||||
|
|
||||||
|
def snippet_delete(request, snippet_id):
|
||||||
|
"""
|
||||||
|
Delete a snippet. This is allowed by anybody as long as he knows the
|
||||||
|
snippet id. I got too many manual requests to do this, mostly for legal
|
||||||
|
reasons and the chance to abuse this is not given anyway, since snippets
|
||||||
|
always expire.
|
||||||
|
"""
|
||||||
snippet = get_object_or_404(Snippet, secret_id=snippet_id)
|
snippet = get_object_or_404(Snippet, secret_id=snippet_id)
|
||||||
"""
|
|
||||||
Anybody can delete anybodys snippets now.
|
|
||||||
|
|
||||||
try:
|
|
||||||
snippet_list = request.session['snippet_list']
|
|
||||||
except KeyError:
|
|
||||||
return HttpResponseForbidden('You have no recent snippet list, cookie error?')
|
|
||||||
if not snippet.pk in snippet_list:
|
|
||||||
return HttpResponseForbidden('That\'s not your snippet!')
|
|
||||||
"""
|
|
||||||
snippet.delete()
|
snippet.delete()
|
||||||
return HttpResponseRedirect(reverse('snippet_new') + '?delete=1')
|
return HttpResponseRedirect(reverse('snippet_new') + '?delete=1')
|
||||||
|
|
||||||
def snippet_history(request, template_name='dpaste/snippet_list.html'):
|
|
||||||
|
|
||||||
|
def snippet_history(request, template_name='dpaste/snippet_list.html'):
|
||||||
|
"""
|
||||||
|
Display the last `n` snippets created by this user (and saved in his
|
||||||
|
session).
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
snippet_list = get_list_or_404(Snippet, pk__in=request.session.get('snippet_list', None))
|
snippet_list = get_list_or_404(Snippet, pk__in=request.session.get('snippet_list', None))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
snippet_list = None
|
snippet_list = None
|
||||||
|
|
||||||
template_context = {
|
template_context = {
|
||||||
'snippets_max': getattr(settings, 'MAX_SNIPPETS_PER_USER', 10),
|
'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10),
|
||||||
'snippet_list': snippet_list,
|
'snippet_list': snippet_list,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +139,9 @@ def snippet_history(request, template_name='dpaste/snippet_list.html'):
|
||||||
|
|
||||||
|
|
||||||
def snippet_diff(request, template_name='dpaste/snippet_diff.html'):
|
def snippet_diff(request, template_name='dpaste/snippet_diff.html'):
|
||||||
|
"""
|
||||||
|
Display a diff between two given snippet secret ids.
|
||||||
|
"""
|
||||||
if request.GET.get('a') and request.GET.get('a').isdigit() \
|
if request.GET.get('a') and request.GET.get('a').isdigit() \
|
||||||
and request.GET.get('b') and request.GET.get('b').isdigit():
|
and request.GET.get('b') and request.GET.get('b').isdigit():
|
||||||
try:
|
try:
|
||||||
|
@ -207,6 +184,7 @@ def snippet_diff(request, template_name='dpaste/snippet_diff.html'):
|
||||||
RequestContext(request)
|
RequestContext(request)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def snippet_gist(request, snippet_id):
|
def snippet_gist(request, snippet_id):
|
||||||
"""
|
"""
|
||||||
Put a snippet on Github Gist.
|
Put a snippet on Github Gist.
|
||||||
|
@ -235,15 +213,58 @@ def snippet_gist(request, snippet_id):
|
||||||
return HttpResponseRedirect(gist_url)
|
return HttpResponseRedirect(gist_url)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Static pages
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
def guess_lexer(request):
|
def about(request, template_name='dpaste/about.html'):
|
||||||
code_string = request.GET.get('codestring', False)
|
"""
|
||||||
response = simplejson.dumps({'lexer': guess_code_lexer(code_string)})
|
A rather static page, we need a view just to display a couple of
|
||||||
|
statistics.
|
||||||
|
"""
|
||||||
|
template_context = {
|
||||||
|
'total': Snippet.objects.count(),
|
||||||
|
'stats': Snippet.objects.values('lexer').annotate(
|
||||||
|
count=Count('lexer')).order_by('-count')[:5],
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_to_response(
|
||||||
|
template_name,
|
||||||
|
template_context,
|
||||||
|
RequestContext(request)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# API Handling
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def snippet_api(request, enclose_quotes=True):
|
||||||
|
content = request.POST.get('content', '').strip()
|
||||||
|
|
||||||
|
if not content:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
s = Snippet.objects.create(
|
||||||
|
content=content,
|
||||||
|
expires=datetime.datetime.now()+datetime.timedelta(seconds=60*60*24*30)
|
||||||
|
)
|
||||||
|
s.save()
|
||||||
|
|
||||||
|
response = 'http://dpaste.de%s' % s.get_absolute_url()
|
||||||
|
if enclose_quotes:
|
||||||
|
return HttpResponse('"%s"' % response)
|
||||||
return HttpResponse(response)
|
return HttpResponse(response)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Custom 404 and 500 views. Its easier to integrate this as a app if we
|
||||||
|
# handle them here.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
def page_not_found(request, template_name='dpaste/404.html'):
|
def page_not_found(request, template_name='dpaste/404.html'):
|
||||||
return django_page_not_found(request, template_name)
|
return django_page_not_found(request, 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)
|
return django_server_error(request, template_name)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
django==1.5.1
|
django==1.5.2
|
||||||
django-mptt==0.4.2
|
django-mptt==0.6.0
|
||||||
pygments==1.6
|
pygments==1.6
|
||||||
south==0.7.6
|
south==0.8.2
|
||||||
requests==1.2.3
|
requests==1.2.3
|
||||||
|
|
||||||
# Deployment specific
|
# Deployment specific
|
||||||
##mysql-python==1.2.4
|
#mysql-python==1.2.4
|
||||||
gunicorn==0.17.2
|
gunicorn==17.5
|
||||||
|
|
Loading…
Reference in a new issue