From 8d10c0bd1e60289ebcca2fb4e038a7b3c6c64ca2 Mon Sep 17 00:00:00 2001
From: Martin Mahner
Date: Tue, 27 Mar 2018 18:42:54 +0200
Subject: [PATCH] POST based snippet delete
---
client/scss/_globals.scss | 32 +++-
client/scss/_mixins.scss | 14 ++
client/scss/components/_article.scss | 11 +-
dpaste/templates/dpaste/details.html | 18 ++-
dpaste/templates/dpaste/history.html | 20 ++-
dpaste/templates/dpaste/includes/form.html | 2 +-
dpaste/urls/dpaste.py | 12 +-
dpaste/views.py | 180 +++++++++++----------
8 files changed, 172 insertions(+), 117 deletions(-)
diff --git a/client/scss/_globals.scss b/client/scss/_globals.scss
index fb69123..79e1190 100644
--- a/client/scss/_globals.scss
+++ b/client/scss/_globals.scss
@@ -11,7 +11,6 @@ body[data-code-snippet] { background-color: $codeBgColor; }
body[data-platform=win] .platform-mac { display: none; }
body[data-platform=mac] .platform-win { display: none; }
-
.btn {
padding: 6px 0;
position: relative;
@@ -45,3 +44,34 @@ body[data-platform=mac] .platform-win { display: none; }
top: 1px;
}
}
+
+.confirm-modal {
+ @include colored-links;
+ background-color: $confirmBgColor;
+ color: $confirmTextColor;
+
+ // Hidden by default
+ overflow: hidden;
+ max-height: 0;
+
+ // Foldout animation
+ transition: max-height .15s ease-in;
+
+ form {
+ display: block;
+ padding: 20px $boxPadding;
+ }
+
+ .btn {
+ padding: 6px 15px;
+ margin: 0 10px;
+ }
+
+ .no {
+ font-size: 13px;
+ }
+
+ &:target {
+ max-height: 80px;
+ }
+}
diff --git a/client/scss/_mixins.scss b/client/scss/_mixins.scss
index bfd64d7..7624601 100644
--- a/client/scss/_mixins.scss
+++ b/client/scss/_mixins.scss
@@ -5,3 +5,17 @@
border-right: 2px dotted $color;
margin: 0 ($margin+2px) 0 $margin;
}
+
+
+@mixin colored-links() {
+ a:link, a:visited {
+ color: $linkColor;
+ text-decoration: underline;
+ text-decoration-color: lighten($linkColor, 30%);
+ }
+
+ a:hover, a:active {
+ color: $hoverColor;
+ text-decoration: underline;
+ }
+}
diff --git a/client/scss/components/_article.scss b/client/scss/components/_article.scss
index 4c8d688..da7615f 100644
--- a/client/scss/components/_article.scss
+++ b/client/scss/components/_article.scss
@@ -29,14 +29,5 @@ article {
font-weight: $baseFontDemiBold;
}
- a:link, a:visited {
- color: $linkColor;
- text-decoration: underline;
- text-decoration-color: lighten($linkColor, 30%);
- }
-
- a:hover, a:active {
- color: $hoverColor;
- text-decoration: underline;
- }
+ @include colored-links;
}
diff --git a/dpaste/templates/dpaste/details.html b/dpaste/templates/dpaste/details.html
index 458b9b1..a7a8427 100644
--- a/dpaste/templates/dpaste/details.html
+++ b/dpaste/templates/dpaste/details.html
@@ -33,15 +33,8 @@
- {% trans "Delete Now" %}
+ {% trans "Delete Now" %}
-
-
{% if snippet.expire_type != 3 %}
{% trans "View Raw" %}
{% endif %}
@@ -53,6 +46,15 @@
{% endif %}
+
+
{% endblock %}
{% block page %}
diff --git a/dpaste/templates/dpaste/history.html b/dpaste/templates/dpaste/history.html
index 7c01ec2..b9cd9a8 100644
--- a/dpaste/templates/dpaste/history.html
+++ b/dpaste/templates/dpaste/history.html
@@ -11,18 +11,28 @@
{% trans "Snippet History" %}
{% if snippet_list %}
+ {% trans "Delete all Snippets" %}
- {% trans "Delete all Snippets" %}
-
-
+ {# Wordwrap is enabled by default for all lexer in the history #}
{% endif %}
+
+
{% endblock %}
{% block page %}
diff --git a/dpaste/templates/dpaste/includes/form.html b/dpaste/templates/dpaste/includes/form.html
index d0aa4eb..fbb1bf5 100644
--- a/dpaste/templates/dpaste/includes/form.html
+++ b/dpaste/templates/dpaste/includes/form.html
@@ -24,7 +24,7 @@
{% trans "⌘+⏎" %}
{% trans "Ctrl+⏎" %}
-
+
diff --git a/dpaste/urls/dpaste.py b/dpaste/urls/dpaste.py
index 8f6af38..38df9dc 100644
--- a/dpaste/urls/dpaste.py
+++ b/dpaste/urls/dpaste.py
@@ -8,14 +8,12 @@ from .. import views
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
urlpatterns = [
- url(r'^about/$', views.AboutView.as_view(), name='dpaste_about'),
-
url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
- url(r'^diff/$', views.SnippetDiffView.as_view(), name='snippet_diff'),
+ url(r'^about/$', views.AboutView.as_view(), name='dpaste_about'),
url(r'^history/$', views.SnippetHistory.as_view(), name='snippet_history'),
- url(r'^delete/$', views.SnippetDeleteView.as_view(), name='snippet_delete'),
- url(r'^(?P[a-zA-Z0-9]{%d,})/?$' % L, views.SnippetDetailView.as_view(), name='snippet_details'),
- url(r'^(?P[a-zA-Z0-9]{%d,})/delete/$' % L, views.SnippetDeleteView.as_view(), name='snippet_delete'),
- url(r'^(?P[a-zA-Z0-9]{%d,})/raw/?$' % L, views.SnippetRawView.as_view(), name='snippet_details_raw'),
+ url(r'^(?P[a-zA-Z0-9]{%d,})/?$' % L,
+ views.SnippetDetailView.as_view(), name='snippet_details'),
+ url(r'^(?P[a-zA-Z0-9]{%d,})/raw/?$' % L,
+ views.SnippetRawView.as_view(), name='snippet_details_raw'),
]
diff --git a/dpaste/views.py b/dpaste/views.py
index 3747423..e253647 100644
--- a/dpaste/views.py
+++ b/dpaste/views.py
@@ -66,6 +66,24 @@ class SnippetDetailView(SnippetView, DetailView):
slug_url_kwarg = 'snippet_id'
slug_field = 'secret_id'
+ def post(self, *args, **kwargs):
+ """
+ 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.
+ """
+ if 'delete' in self.request.POST:
+ snippet = get_object_or_404(Snippet, secret_id=self.kwargs['snippet_id'])
+ snippet.delete()
+
+ # Append `#` so #delete goes away in Firefox
+ url = '{0}#'.format(reverse('snippet_new'))
+ return HttpResponseRedirect(url)
+
+ return super(SnippetDetailView, self).post(*args, **kwargs)
+
+
def get(self, *args, **kwargs):
snippet = self.get_object()
@@ -101,6 +119,7 @@ class SnippetDetailView(SnippetView, DetailView):
})
return ctx
+
class SnippetRawView(SnippetDetailView):
"""
Display the raw content of a snippet
@@ -113,22 +132,6 @@ class SnippetRawView(SnippetDetailView):
return response
-class SnippetDeleteView(View):
- """
- 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.
- """
- def dispatch(self, request, *args, **kwargs):
- snippet_id = self.kwargs.get('snippet_id') or request.POST.get('snippet_id')
- if not snippet_id:
- raise Http404('No snippet id given')
- snippet = get_object_or_404(Snippet, secret_id=snippet_id)
- snippet.delete()
- return HttpResponseRedirect(reverse('snippet_new'))
-
-
class SnippetHistory(TemplateView):
"""
Display the last `n` snippets created by this user (and saved in his
@@ -136,85 +139,92 @@ class SnippetHistory(TemplateView):
"""
template_name = 'dpaste/history.html'
- def get(self, request, *args, **kwargs):
- snippet_id_list = request.session.get('snippet_list', [])
- self.snippet_list = Snippet.objects.filter(pk__in=snippet_id_list)
+ def get_user_snippets(self):
+ snippet_id_list = self.request.session.get('snippet_list', [])
+ return Snippet.objects.filter(pk__in=snippet_id_list)
+
+ def post(self, *args, **kwargs):
+ """
+ Delete all user snippets at once.
+ """
+ if 'delete' in self.request.POST:
+ self.get_user_snippets().delete()
+
+ # Append `#` so #delete goes away in Firefox
+ url = '{0}#'.format(reverse('snippet_history'))
+ return HttpResponseRedirect(url)
- if 'delete-all' in request.GET:
- self.snippet_list.delete()
- return HttpResponseRedirect(reverse('snippet_history'))
- return super(SnippetHistory, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
ctx.update({
'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10),
- 'snippet_list': self.snippet_list,
+ 'snippet_list': self.get_user_snippets(),
})
return ctx
-class SnippetDiffView(TemplateView):
- """
- Display a diff between two given snippet secret ids.
- """
- template_name = 'dpaste/includes/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() \
- and request.GET.get('b') and request.GET.get('b').isdigit():
- try:
- self.fileA = Snippet.objects.get(pk=int(request.GET.get('a')))
- self.fileB = Snippet.objects.get(pk=int(request.GET.get('b')))
- except ObjectDoesNotExist:
- return HttpResponseBadRequest(u'Selected file(s) does not exist.')
- else:
- return HttpResponseBadRequest(u'You must select two snippets.')
-
- return super(SnippetDiffView, self).get(request, *args, **kwargs)
-
- def get_diff(self):
- class DiffText(object):
- pass
-
- diff = DiffText()
-
- if self.fileA.content != self.fileB.content:
- d = difflib.unified_diff(
- self.fileA.content.splitlines(),
- self.fileB.content.splitlines(),
- 'Original',
- 'Current',
- lineterm=''
- )
-
- diff.content = '\n'.join(d).strip()
- diff.lexer = 'diff'
- else:
- diff.content = force_text(_(u'No changes were made between this two files.'))
- diff.lexer = 'text'
-
- return diff
-
- def highlight_snippet(self, content):
- h = highlight.pygmentize(content, 'diff')
- h = h.replace(u'\t', ' ')
- return h
-
- def get_context_data(self, **kwargs):
- diff = self.get_diff()
- highlighted = self.highlight_snippet(diff.content)
- ctx = super(SnippetDiffView, self).get_context_data(**kwargs)
- ctx.update({
- 'snippet': diff,
- 'highlighted': highlighted.splitlines(),
- 'fileA': self.fileA,
- 'fileB': self.fileB,
- })
- return ctx
+# class SnippetDiffView(TemplateView):
+# """
+# Display a diff between two given snippet secret ids.
+# """
+# template_name = 'dpaste/includes/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() \
+# and request.GET.get('b') and request.GET.get('b').isdigit():
+# try:
+# self.fileA = Snippet.objects.get(pk=int(request.GET.get('a')))
+# self.fileB = Snippet.objects.get(pk=int(request.GET.get('b')))
+# except ObjectDoesNotExist:
+# return HttpResponseBadRequest(u'Selected file(s) does not exist.')
+# else:
+# return HttpResponseBadRequest(u'You must select two snippets.')
+#
+# return super(SnippetDiffView, self).get(request, *args, **kwargs)
+#
+# def get_diff(self):
+# class DiffText(object):
+# pass
+#
+# diff = DiffText()
+#
+# if self.fileA.content != self.fileB.content:
+# d = difflib.unified_diff(
+# self.fileA.content.splitlines(),
+# self.fileB.content.splitlines(),
+# 'Original',
+# 'Current',
+# lineterm=''
+# )
+#
+# diff.content = '\n'.join(d).strip()
+# diff.lexer = 'diff'
+# else:
+# diff.content = force_text(_(u'No changes were made between this two files.'))
+# diff.lexer = 'text'
+#
+# return diff
+#
+# def highlight_snippet(self, content):
+# h = highlight.pygmentize(content, 'diff')
+# h = h.replace(u'\t', ' ')
+# return h
+#
+# def get_context_data(self, **kwargs):
+# diff = self.get_diff()
+# highlighted = self.highlight_snippet(diff.content)
+# ctx = super(SnippetDiffView, self).get_context_data(**kwargs)
+# ctx.update({
+# 'snippet': diff,
+# 'highlighted': highlighted.splitlines(),
+# 'fileA': self.fileA,
+# 'fileB': self.fileB,
+# })
+# return ctx
# -----------------------------------------------------------------------------