POST based snippet delete

This commit is contained in:
Martin Mahner 2018-03-27 18:42:54 +02:00
parent 38dd6f5c89
commit 8d10c0bd1e
8 changed files with 172 additions and 117 deletions

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -33,15 +33,8 @@
</li>
<li class="sep"></li>
<li>
<a href="{% url "snippet_delete" snippet.secret_id %}"
onclick="return confirm('{% trans "Are you sure you want to delete this snippet?" %}');">{% trans "Delete Now" %}</a>
<a href="#delete">{% trans "Delete Now" %}</a>
</li>
<!--
{% if snippet.parent %}
<li><a href="#snippet-diff">{% trans "Compare with previous Snippet" %}</a></li>
{% endif %}
-->
{% if snippet.expire_type != 3 %}
<li><a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a></li>
{% endif %}
@ -53,6 +46,15 @@
</li>
{% endif %}
</ul>
<div id="delete" class="confirm-modal">
<form method="POST" action="">
{% csrf_token %}
{% trans "Are you sure to delete this snippet?" %}
<button class="btn" name="delete" value="1" type="submit">{% trans "Yes, Delete" %}</button>
<a href="#" class="no">{% trans "No, don't delete" %}</a>
</form>
</div>
{% endblock %}
{% block page %}

View file

@ -11,18 +11,28 @@
<li>{% trans "Snippet History" %}</li>
{% if snippet_list %}
<li class="sep"></li>
<li><a href="#delete">{% trans "Delete all Snippets" %}</a></li>
<li>
<a href="?delete-all"
onclick="return confirm('{% trans "Are you sure you want to delete all snippets?" %}');">{% trans "Delete all Snippets" %}</a>
</li>
<li>
{# Wordwrap is enabled by default for all lexer in the history #}
<label for="wordwrap">
{# Wordwrap is enabled by default for all lexer in the history #}
<input type="checkbox" id="wordwrap" checked> Wordwrap
</label>
</li>
{% endif %}
</ul>
<div id="delete" class="confirm-modal">
<form method="POST" action="">
{% csrf_token %}
{% blocktrans count snippet_list|length as count %}
Do you really want to delete the snippet below?
{% plural %}
Do you really want to delete the {{ count }} snippets below?
{% endblocktrans %}
<button class="btn" name="delete" value="1" type="submit">{% trans "Yes, Delete All" %}</button>
<a href="#" class="no">{% trans "No, don't delete" %}</a>
</form>
</div>
{% endblock %}
{% block page %}

View file

@ -24,7 +24,7 @@
<span class="sep"></span>
<span class="platform-mac">{% trans "&#8984;+&#9166;" %}</span>
<span class="platform-win">{% trans "Ctrl+&#9166;" %}</span>
</button>
</button>
</p>
</div>

View file

@ -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<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,})/raw/?$' % L, views.SnippetRawView.as_view(), name='snippet_details_raw'),
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,})/raw/?$' % L,
views.SnippetRawView.as_view(), name='snippet_details_raw'),
]

View file

@ -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', '&nbsp;&nbsp;&nbsp;&nbsp;')
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', '&nbsp;&nbsp;&nbsp;&nbsp;')
# 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
# -----------------------------------------------------------------------------