Make all views class-based.

This commit is contained in:
Martin Mahner 2016-03-24 20:14:13 +01:00
parent 82d49d0ed1
commit 1c2e26c930
4 changed files with 228 additions and 207 deletions

View file

@ -2,34 +2,34 @@
<form method="post" action="" class="form-horizontal"> <form method="post" action="" class="form-horizontal">
{% csrf_token %} {% csrf_token %}
{{ snippet_form.non_field_errors }} {{ form.non_field_errors }}
<div style="display: none;">{{ snippet_form.title }}</div> <div style="display: none;">{{ form.title }}</div>
<div class=" <div class="
control-group control-group
form-content form-content
superenter superenter
{% if is_new %}autofocus{% endif %} {% if not object %}autofocus{% endif %}
{% if snippet_form.content.errors %}error{% endif %} {% if form.content.errors %}error{% endif %}
"> ">
{{ snippet_form.content }} {{ form.content }}
</div> </div>
<div class="control-group form-options"> <div class="control-group form-options">
<div class="form-options-lexer <div class="form-options-lexer
{% if snippet_form.lexer.errors %}control-group error{% endif %}"> {% if form.lexer.errors %}control-group error{% endif %}">
<div class="input-append"> <div class="input-append">
{{ snippet_form.lexer }} {{ form.lexer }}
</div> </div>
{% for error in snippet_form.lexer.errors %} {% for error in form.lexer.errors %}
<span class="help-inline">{{ error }}</span> <span class="help-inline">{{ error }}</span>
{% endfor %} {% endfor %}
</div> </div>
<div class="form-options-expire"> <div class="form-options-expire">
{{ snippet_form.expires.errors }} {{ form.expires.errors }}
<div class="input-prepend"> <div class="input-prepend">
<span class="add-on"><i class="icon-trash" title="{% trans "Expire in" %}"></i></span> <span class="add-on"><i class="icon-trash" title="{% trans "Expire in" %}"></i></span>
{{ snippet_form.expires }} {{ form.expires }}
</div> </div>
</div> </div>
</div> </div>

View file

@ -6,14 +6,15 @@ from .. import views
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4) L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
urlpatterns = [ urlpatterns = [
url(r'^about/$', views.about, name='dpaste_about'), url(r'^about/$', views.AboutView.as_view(), name='dpaste_about'),
url(r'^$', views.snippet_new, name='snippet_new'), url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
url(r'^diff/$', views.snippet_diff, name='snippet_diff'), url(r'^diff/$', views.SnippetDiffView.as_view(), name='snippet_diff'),
url(r'^history/$', views.snippet_history, name='snippet_history'), url(r'^history/$', views.SnippetHistory.as_view(), name='snippet_history'),
url(r'^delete/$', views.snippet_delete, name='snippet_delete'), url(r'^delete/$', views.SnippetDeleteView.as_view(), name='snippet_delete'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L, views.snippet_details, name='snippet_details'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/delete/$' % L, views.snippet_delete, name='snippet_delete'), url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L, views.SnippetDetailView.as_view(), name='snippet_details'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/delete/$' % L, views.SnippetDeleteView.as_view(), name='snippet_delete'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/gist/$' % L, views.snippet_gist, name='snippet_gist'), url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/gist/$' % L, views.snippet_gist, name='snippet_gist'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L, views.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]{%d,})/raw/?$' % L, views.SnippetRawView.as_view(), name='snippet_details_raw'),
] ]

View file

@ -1,7 +1,7 @@
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
from ..views import snippet_api from ..views import APIView
urlpatterns = [ urlpatterns = [
url(r'^api/$', snippet_api, name='dpaste_api_create_snippet'), url(r'^api/$', APIView.as_view(), name='dpaste_api_create_snippet'),
] ]

View file

@ -9,12 +9,14 @@ from django.core.urlresolvers import reverse
from django.db.models import Count from django.db.models import Count
from django.http import (Http404, HttpResponse, HttpResponseBadRequest, from django.http import (Http404, HttpResponse, HttpResponseBadRequest,
HttpResponseRedirect) HttpResponseRedirect)
from django.shortcuts import get_object_or_404, render_to_response from django.shortcuts import get_object_or_404
from django.template.context import RequestContext from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
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
from django.views.defaults import server_error as django_server_error from django.views.defaults import server_error as django_server_error
from django.views.generic.base import View, TemplateView
from django.views.generic.detail import DetailView
from pygments.lexers import get_lexer_for_filename from pygments.lexers import get_lexer_for_filename
from pygments.util import ClassNotFound from pygments.util import ClassNotFound
@ -33,38 +35,47 @@ template_globals = {
# Snippet Handling # Snippet Handling
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def snippet_new(request, template_name='dpaste/snippet_new.html'): from django.views.generic import FormView
class SnippetView(FormView):
""" """
Create a new snippet. Create a new snippet.
""" """
if request.method == "POST": form_class = SnippetForm
snippet_form = SnippetForm(data=request.POST, request=request) template_name = 'dpaste/snippet_new.html'
if snippet_form.is_valid():
new_snippet = snippet_form.save()
url = new_snippet.get_absolute_url()
return HttpResponseRedirect(url)
else:
snippet_form = SnippetForm(request=request)
template_context = { def get_form_kwargs(self):
'snippet_form': snippet_form, kwargs = super(SnippetView, self).get_form_kwargs()
kwargs.update({
'request': self.request,
})
return kwargs
def get_context_data(self, **kwargs):
ctx = super(SnippetView, self).get_context_data(**kwargs)
ctx.update(template_globals)
ctx.update({
'lexer_list': LEXER_LIST, 'lexer_list': LEXER_LIST,
'is_new': True, })
} return ctx
return render_to_response( def form_valid(self, form):
template_name, snippet = form.save()
template_context, return HttpResponseRedirect(snippet.get_absolute_url())
RequestContext(request, template_globals)
)
def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.html', is_raw=False): 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.
""" """
snippet = get_object_or_404(Snippet, secret_id=snippet_id) queryset = Snippet.objects.all()
template_name = 'dpaste/snippet_details.html'
slug_url_kwarg = 'snippet_id'
slug_field = 'secret_id'
def get(self, *args, **kwargs):
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 \ if snippet.expire_type == Snippet.EXPIRE_ONETIME \
@ -76,60 +87,57 @@ def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.h
snippet.view_count += 1 snippet.view_count += 1
snippet.save() snippet.save()
tree = snippet.get_root() return super(SnippetDetailView, self).get(*args, **kwargs)
tree = tree.get_descendants(include_self=True)
new_snippet_initial = { def get_initial(self):
snippet = self.get_object()
return {
'content': snippet.content, 'content': snippet.content,
'lexer': snippet.lexer, 'lexer': snippet.lexer,
} }
if request.method == "POST": def form_valid(self, form):
snippet_form = SnippetForm( snippet = form.save(parent=self.get_object())
data=request.POST, return HttpResponseRedirect(snippet.get_absolute_url())
request=request,
initial=new_snippet_initial)
if snippet_form.is_valid():
new_snippet = snippet_form.save(parent=snippet)
url = new_snippet.get_absolute_url()
return HttpResponseRedirect(url)
else:
snippet_form = SnippetForm(
initial=new_snippet_initial,
request=request)
template_context = { def get_context_data(self, **kwargs):
'snippet_form': snippet_form, self.object = snippet = self.get_object()
'snippet': snippet, tree = snippet.get_root().get_descendants(include_self=True)
'lexers': LEXER_LIST,
ctx = super(SnippetDetailView, self).get_context_data(**kwargs)
ctx.update(template_globals)
ctx.update({
'lines': range(snippet.get_linecount()), 'lines': range(snippet.get_linecount()),
'tree': tree, 'tree': tree,
'wordwrap': snippet.lexer in LEXER_WORDWRAP and 'True' or 'False', 'wordwrap': snippet.lexer in LEXER_WORDWRAP and 'True' or 'False',
'gist': getattr(settings, 'DPASTE_ENABLE_GIST', True), 'gist': getattr(settings, 'DPASTE_ENABLE_GIST', True),
} })
return ctx
response = render_to_response(
template_name,
template_context,
RequestContext(request, template_globals)
)
if is_raw: class SnippetRawView(SnippetDetailView):
"""
Display the raw content of a snippet
"""
template_name = 'dpaste/snippet_details_raw.html'
def render_to_response(self, context, **response_kwargs):
snippet = self.get_object()
response = HttpResponse(snippet.content)
response['Content-Type'] = 'text/plain;charset=UTF-8' response['Content-Type'] = 'text/plain;charset=UTF-8'
response['X-Content-Type-Options'] = 'nosniff' response['X-Content-Type-Options'] = 'nosniff'
return response return response
else:
return response
def snippet_delete(request, snippet_id=None): class SnippetDeleteView(View):
""" """
Delete a snippet. This is allowed by anybody as long as he knows the 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 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 reasons and the chance to abuse this is not given anyway, since snippets
always expire. always expire.
""" """
snippet_id = snippet_id or request.POST.get('snippet_id') def dispatch(self, request, *args, **kwargs):
snippet_id = self.kwargs.get('snippet_id') or request.POST.get('snippet_id')
if not snippet_id: if not snippet_id:
raise Http404('No snippet id given') raise Http404('No snippet id given')
snippet = get_object_or_404(Snippet, secret_id=snippet_id) snippet = get_object_or_404(Snippet, secret_id=snippet_id)
@ -137,57 +145,64 @@ def snippet_delete(request, snippet_id=None):
return HttpResponseRedirect(reverse('snippet_new')) return HttpResponseRedirect(reverse('snippet_new'))
def snippet_history(request, template_name='dpaste/snippet_list.html'): 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).
""" """
snippet_list = None template_name = 'dpaste/snippet_list.html'
snippet_id_list = request.session.get('snippet_list', None)
if snippet_id_list: def get(self, request, *args, **kwargs):
snippet_list = Snippet.objects.filter(pk__in=snippet_id_list) snippet_id_list = request.session.get('snippet_list', [])
self.snippet_list = Snippet.objects.filter(pk__in=snippet_id_list)
if 'delete-all' in request.GET: if 'delete-all' in request.GET:
if snippet_list: self.snippet_list.delete()
for s in snippet_list:
s.delete()
return HttpResponseRedirect(reverse('snippet_history')) return HttpResponseRedirect(reverse('snippet_history'))
return super(SnippetHistory, self).get(request, *args, **kwargs)
template_context = { def get_context_data(self, **kwargs):
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
ctx.update(template_globals)
ctx.update({
'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10), 'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10),
'snippet_list': snippet_list, 'snippet_list': self.snippet_list,
} })
return ctx
return render_to_response(
template_name,
template_context,
RequestContext(request, template_globals)
)
def snippet_diff(request, template_name='dpaste/snippet_diff.html'): class SnippetDiffView(TemplateView):
""" """
Display a diff between two given snippet secret ids. Display a diff between two given snippet secret ids.
""" """
template_name = 'dpaste/snippet_diff.html'
def get(self, request, *args, **kwargs):
"""
Some validation around input files we will compare later.
"""
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:
fileA = Snippet.objects.get(pk=int(request.GET.get('a'))) self.fileA = Snippet.objects.get(pk=int(request.GET.get('a')))
fileB = Snippet.objects.get(pk=int(request.GET.get('b'))) self.fileB = Snippet.objects.get(pk=int(request.GET.get('b')))
except ObjectDoesNotExist: except ObjectDoesNotExist:
return HttpResponseBadRequest(u'Selected file(s) does not exist.') return HttpResponseBadRequest(u'Selected file(s) does not exist.')
else: else:
return HttpResponseBadRequest(u'You must select two snippets.') return HttpResponseBadRequest(u'You must select two snippets.')
return super(SnippetDiffView, self).get(request, *args, **kwargs)
def get_diff(self):
class DiffText(object): class DiffText(object):
pass pass
diff = DiffText() diff = DiffText()
if fileA.content != fileB.content: if self.fileA.content != self.fileB.content:
d = difflib.unified_diff( d = difflib.unified_diff(
fileA.content.splitlines(), self.fileA.content.splitlines(),
fileB.content.splitlines(), self.fileB.content.splitlines(),
'Original', 'Original',
'Current', 'Current',
lineterm='' lineterm=''
@ -199,17 +214,17 @@ def snippet_diff(request, template_name='dpaste/snippet_diff.html'):
diff.content = _(u'No changes were made between this two files.') diff.content = _(u'No changes were made between this two files.')
diff.lexer = 'text' diff.lexer = 'text'
template_context = { return diff
'snippet': diff,
'fileA': fileA,
'fileB': fileB,
}
return render_to_response( def get_context_data(self, **kwargs):
template_name, ctx = super(SnippetDiffView, self).get_context_data(**kwargs)
template_context, ctx.update(template_globals)
RequestContext(request, template_globals) ctx.update({
) 'snippet': self.get_diff(),
'fileA': self.fileA,
'fileB': self.fileB,
})
return ctx
def snippet_gist(request, snippet_id): # pragma: no cover def snippet_gist(request, snippet_id): # pragma: no cover
@ -247,22 +262,22 @@ def snippet_gist(request, snippet_id): # pragma: no cover
# Static pages # Static pages
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def about(request, template_name='dpaste/about.html'): class AboutView(TemplateView):
""" """
A rather static page, we need a view just to display a couple of A rather static page, we need a view just to display a couple of
statistics. statistics.
""" """
template_context = { template_name = 'dpaste/about.html'
def get_context_data(self, **kwargs):
ctx = super(AboutView, self).get_context_data(**kwargs)
ctx.update(template_globals)
ctx.update({
'total': Snippet.objects.count(), 'total': Snippet.objects.count(),
'stats': Snippet.objects.values('lexer').annotate( 'stats': Snippet.objects.values('lexer').annotate(
count=Count('lexer')).order_by('-count')[:5], count=Count('lexer')).order_by('-count')[:5],
} })
return ctx
return render_to_response(
template_name,
template_context,
RequestContext(request, template_globals)
)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -293,8 +308,13 @@ FORMAT_MAPPING = {
'json': _format_json, 'json': _format_json,
} }
@csrf_exempt
def snippet_api(request): class APIView(View):
"""
API View
"""
@method_decorator(csrf_exempt)
def post(self, request, *args, **kwargs):
content = request.POST.get('content', '').strip() content = request.POST.get('content', '').strip()
lexer = request.POST.get('lexer', LEXER_DEFAULT).strip() lexer = request.POST.get('lexer', LEXER_DEFAULT).strip()
filename = request.POST.get('filename', '').strip() filename = request.POST.get('filename', '').strip()