mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 08:02:54 +11:00
POST based snippet delete
This commit is contained in:
parent
38dd6f5c89
commit
8d10c0bd1e
8 changed files with 172 additions and 117 deletions
|
@ -11,7 +11,6 @@ body[data-code-snippet] { background-color: $codeBgColor; }
|
||||||
body[data-platform=win] .platform-mac { display: none; }
|
body[data-platform=win] .platform-mac { display: none; }
|
||||||
body[data-platform=mac] .platform-win { display: none; }
|
body[data-platform=mac] .platform-win { display: none; }
|
||||||
|
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -45,3 +44,34 @@ body[data-platform=mac] .platform-win { display: none; }
|
||||||
top: 1px;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,3 +5,17 @@
|
||||||
border-right: 2px dotted $color;
|
border-right: 2px dotted $color;
|
||||||
margin: 0 ($margin+2px) 0 $margin;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,14 +29,5 @@ article {
|
||||||
font-weight: $baseFontDemiBold;
|
font-weight: $baseFontDemiBold;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link, a:visited {
|
@include colored-links;
|
||||||
color: $linkColor;
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: lighten($linkColor, 30%);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover, a:active {
|
|
||||||
color: $hoverColor;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,15 +33,8 @@
|
||||||
</li>
|
</li>
|
||||||
<li class="sep"></li>
|
<li class="sep"></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url "snippet_delete" snippet.secret_id %}"
|
<a href="#delete">{% trans "Delete Now" %}</a>
|
||||||
onclick="return confirm('{% trans "Are you sure you want to delete this snippet?" %}');">{% trans "Delete Now" %}</a>
|
|
||||||
</li>
|
</li>
|
||||||
<!--
|
|
||||||
{% if snippet.parent %}
|
|
||||||
<li><a href="#snippet-diff">{% trans "Compare with previous Snippet" %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
-->
|
|
||||||
|
|
||||||
{% if snippet.expire_type != 3 %}
|
{% if snippet.expire_type != 3 %}
|
||||||
<li><a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a></li>
|
<li><a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -53,6 +46,15 @@
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page %}
|
{% block page %}
|
||||||
|
|
|
@ -11,18 +11,28 @@
|
||||||
<li>{% trans "Snippet History" %}</li>
|
<li>{% trans "Snippet History" %}</li>
|
||||||
{% if snippet_list %}
|
{% if snippet_list %}
|
||||||
<li class="sep"></li>
|
<li class="sep"></li>
|
||||||
|
<li><a href="#delete">{% trans "Delete all Snippets" %}</a></li>
|
||||||
<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>
|
|
||||||
<label for="wordwrap">
|
|
||||||
{# Wordwrap is enabled by default for all lexer in the history #}
|
{# Wordwrap is enabled by default for all lexer in the history #}
|
||||||
|
<label for="wordwrap">
|
||||||
<input type="checkbox" id="wordwrap" checked> Wordwrap
|
<input type="checkbox" id="wordwrap" checked> Wordwrap
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page %}
|
{% block page %}
|
||||||
|
|
|
@ -8,14 +8,12 @@ from .. import views
|
||||||
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
|
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^about/$', views.AboutView.as_view(), name='dpaste_about'),
|
|
||||||
|
|
||||||
url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
|
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'^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,})/?$' % L,
|
||||||
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/delete/$' % L, views.SnippetDeleteView.as_view(), name='snippet_delete'),
|
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'),
|
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L,
|
||||||
|
views.SnippetRawView.as_view(), name='snippet_details_raw'),
|
||||||
]
|
]
|
||||||
|
|
180
dpaste/views.py
180
dpaste/views.py
|
@ -66,6 +66,24 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
slug_url_kwarg = 'snippet_id'
|
slug_url_kwarg = 'snippet_id'
|
||||||
slug_field = 'secret_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):
|
def get(self, *args, **kwargs):
|
||||||
snippet = self.get_object()
|
snippet = self.get_object()
|
||||||
|
|
||||||
|
@ -101,6 +119,7 @@ class SnippetDetailView(SnippetView, DetailView):
|
||||||
})
|
})
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
class SnippetRawView(SnippetDetailView):
|
class SnippetRawView(SnippetDetailView):
|
||||||
"""
|
"""
|
||||||
Display the raw content of a snippet
|
Display the raw content of a snippet
|
||||||
|
@ -113,22 +132,6 @@ class SnippetRawView(SnippetDetailView):
|
||||||
return response
|
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):
|
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
|
||||||
|
@ -136,85 +139,92 @@ class SnippetHistory(TemplateView):
|
||||||
"""
|
"""
|
||||||
template_name = 'dpaste/history.html'
|
template_name = 'dpaste/history.html'
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get_user_snippets(self):
|
||||||
snippet_id_list = request.session.get('snippet_list', [])
|
snippet_id_list = self.request.session.get('snippet_list', [])
|
||||||
self.snippet_list = Snippet.objects.filter(pk__in=snippet_id_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):
|
def get_context_data(self, **kwargs):
|
||||||
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
|
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
|
||||||
ctx.update({
|
ctx.update({
|
||||||
'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10),
|
'snippets_max': getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10),
|
||||||
'snippet_list': self.snippet_list,
|
'snippet_list': self.get_user_snippets(),
|
||||||
})
|
})
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
class SnippetDiffView(TemplateView):
|
# class SnippetDiffView(TemplateView):
|
||||||
"""
|
# """
|
||||||
Display a diff between two given snippet secret ids.
|
# Display a diff between two given snippet secret ids.
|
||||||
"""
|
# """
|
||||||
template_name = 'dpaste/includes/diff.html'
|
# template_name = 'dpaste/includes/diff.html'
|
||||||
|
#
|
||||||
def get(self, request, *args, **kwargs):
|
# def get(self, request, *args, **kwargs):
|
||||||
"""
|
# """
|
||||||
Some validation around input files we will compare later.
|
# 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:
|
||||||
self.fileA = Snippet.objects.get(pk=int(request.GET.get('a')))
|
# self.fileA = Snippet.objects.get(pk=int(request.GET.get('a')))
|
||||||
self.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)
|
# return super(SnippetDiffView, self).get(request, *args, **kwargs)
|
||||||
|
#
|
||||||
def get_diff(self):
|
# def get_diff(self):
|
||||||
class DiffText(object):
|
# class DiffText(object):
|
||||||
pass
|
# pass
|
||||||
|
#
|
||||||
diff = DiffText()
|
# diff = DiffText()
|
||||||
|
#
|
||||||
if self.fileA.content != self.fileB.content:
|
# if self.fileA.content != self.fileB.content:
|
||||||
d = difflib.unified_diff(
|
# d = difflib.unified_diff(
|
||||||
self.fileA.content.splitlines(),
|
# self.fileA.content.splitlines(),
|
||||||
self.fileB.content.splitlines(),
|
# self.fileB.content.splitlines(),
|
||||||
'Original',
|
# 'Original',
|
||||||
'Current',
|
# 'Current',
|
||||||
lineterm=''
|
# lineterm=''
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
diff.content = '\n'.join(d).strip()
|
# diff.content = '\n'.join(d).strip()
|
||||||
diff.lexer = 'diff'
|
# diff.lexer = 'diff'
|
||||||
else:
|
# else:
|
||||||
diff.content = force_text(_(u'No changes were made between this two files.'))
|
# diff.content = force_text(_(u'No changes were made between this two files.'))
|
||||||
diff.lexer = 'text'
|
# diff.lexer = 'text'
|
||||||
|
#
|
||||||
return diff
|
# return diff
|
||||||
|
#
|
||||||
def highlight_snippet(self, content):
|
# def highlight_snippet(self, content):
|
||||||
h = highlight.pygmentize(content, 'diff')
|
# h = highlight.pygmentize(content, 'diff')
|
||||||
h = h.replace(u'\t', ' ')
|
# h = h.replace(u'\t', ' ')
|
||||||
return h
|
# return h
|
||||||
|
#
|
||||||
def get_context_data(self, **kwargs):
|
# def get_context_data(self, **kwargs):
|
||||||
diff = self.get_diff()
|
# diff = self.get_diff()
|
||||||
highlighted = self.highlight_snippet(diff.content)
|
# highlighted = self.highlight_snippet(diff.content)
|
||||||
ctx = super(SnippetDiffView, self).get_context_data(**kwargs)
|
# ctx = super(SnippetDiffView, self).get_context_data(**kwargs)
|
||||||
ctx.update({
|
# ctx.update({
|
||||||
'snippet': diff,
|
# 'snippet': diff,
|
||||||
'highlighted': highlighted.splitlines(),
|
# 'highlighted': highlighted.splitlines(),
|
||||||
'fileA': self.fileA,
|
# 'fileA': self.fileA,
|
||||||
'fileB': self.fileB,
|
# 'fileB': self.fileB,
|
||||||
})
|
# })
|
||||||
return ctx
|
# return ctx
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue