mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 16:12:51 +11:00
Added a API value to set the expire time of snippets. Closes issue #64.
This commit is contained in:
parent
afafd4fb3b
commit
34181e03f7
5 changed files with 113 additions and 33 deletions
21
docs/api.rst
21
docs/api.rst
|
@ -15,18 +15,18 @@ Available POST data for an API call:
|
||||||
``content`` (required)
|
``content`` (required)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Required. The UTF-8 encoded string you want to paste.
|
The UTF-8 encoded string you want to paste.
|
||||||
|
|
||||||
``lexer`` (optional)
|
``lexer`` (optional)
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Optional. Can also be set via GET. The lexer string key used for highlighting.
|
Can also be set via GET. The lexer string key used for highlighting.
|
||||||
See `lexer list`_ for a full list of choices. Default: ``python``.
|
See `lexer list`_ for a full list of choices. Default: ``python``.
|
||||||
|
|
||||||
``format`` (optional)
|
``format`` (optional)
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Optional. Can also be set via GET. The format of the API response. Choices are:
|
Can also be set via GET. The format of the API response. Choices are:
|
||||||
|
|
||||||
* ``default`` — Returns a full qualified URL wrapped in quotes. Example::
|
* ``default`` — Returns a full qualified URL wrapped in quotes. Example::
|
||||||
|
|
||||||
|
@ -47,6 +47,21 @@ Optional. Can also be set via GET. The format of the API response. Choices are:
|
||||||
"conent": "The text body of the snippet."
|
"conent": "The text body of the snippet."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
``expires`` (optional)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Can also be set via GET. A keyword to indicate the lifetime of a
|
||||||
|
snippetn in seconds. The values are predefined by the server. Calling this with
|
||||||
|
an invalid value returns a HTTP 400 BadRequest together with a list of valid
|
||||||
|
values. Default: ``2592000``. In the default configuration valid values are:
|
||||||
|
|
||||||
|
* onetime
|
||||||
|
* never
|
||||||
|
* 3600
|
||||||
|
* 604800
|
||||||
|
* 2592000
|
||||||
|
|
||||||
.. hint:: You need to adjust the setting ``DPASTE_BASE_URL`` which is used
|
.. hint:: You need to adjust the setting ``DPASTE_BASE_URL`` which is used
|
||||||
to generate the full qualified URL in the API response. See :doc:`settings`.
|
to generate the full qualified URL in the API response. See :doc:`settings`.
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,20 @@ EXPIRE_CHOICES = getattr(settings, 'DPASTE_EXPIRE_CHOICES', (
|
||||||
EXPIRE_DEFAULT = getattr(settings, 'DPASTE_EXPIRE_DEFAULT', EXPIRE_CHOICES[3][0])
|
EXPIRE_DEFAULT = getattr(settings, 'DPASTE_EXPIRE_DEFAULT', EXPIRE_CHOICES[3][0])
|
||||||
MAX_CONTENT_LENGTH = getattr(settings, 'DPASTE_MAX_CONTENT_LENGTH', 250*1024*1024)
|
MAX_CONTENT_LENGTH = getattr(settings, 'DPASTE_MAX_CONTENT_LENGTH', 250*1024*1024)
|
||||||
|
|
||||||
|
def get_expire_values(expires):
|
||||||
|
if expires == u'never':
|
||||||
|
expire_type = Snippet.EXPIRE_KEEP
|
||||||
|
expires = None
|
||||||
|
elif expires == u'onetime':
|
||||||
|
expire_type = Snippet.EXPIRE_ONETIME
|
||||||
|
expires = None
|
||||||
|
else:
|
||||||
|
expire_type = Snippet.EXPIRE_TIME
|
||||||
|
expires = expires and expires or EXPIRE_DEFAULT
|
||||||
|
expires = datetime.datetime.now() + datetime.timedelta(seconds=int(expires))
|
||||||
|
return expires, expire_type
|
||||||
|
|
||||||
|
|
||||||
class SnippetForm(forms.ModelForm):
|
class SnippetForm(forms.ModelForm):
|
||||||
content = forms.CharField(
|
content = forms.CharField(
|
||||||
label=_('Content'),
|
label=_('Content'),
|
||||||
|
@ -71,43 +85,35 @@ class SnippetForm(forms.ModelForm):
|
||||||
raise forms.ValidationError(_('Plesae fill out this field.'))
|
raise forms.ValidationError(_('Plesae fill out this field.'))
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
def clean_expires(self):
|
||||||
|
"""
|
||||||
|
Extract the 'expire_type' from the choice of expire choices.
|
||||||
|
"""
|
||||||
|
expires = self.cleaned_data['expires']
|
||||||
|
expires, expire_type = get_expire_values(expires)
|
||||||
|
self.cleaned_data['expire_type'] = expire_type
|
||||||
|
return expires
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
# The `title` field is a hidden honeypot field. If its filled,
|
"""
|
||||||
# this is likely spam.
|
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 clean_expires(self):
|
|
||||||
expires = self.cleaned_data['expires']
|
|
||||||
|
|
||||||
if expires == u'never':
|
|
||||||
self.cleaned_data['expire_type'] = Snippet.EXPIRE_KEEP
|
|
||||||
return None
|
|
||||||
|
|
||||||
if expires == u'onetime':
|
|
||||||
self.cleaned_data['expire_type'] = Snippet.EXPIRE_ONETIME
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.cleaned_data['expire_type'] = Snippet.EXPIRE_TIME
|
|
||||||
return expires
|
|
||||||
|
|
||||||
def save(self, parent=None, *args, **kwargs):
|
def save(self, parent=None, *args, **kwargs):
|
||||||
MAX_SNIPPETS_PER_USER = getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10)
|
MAX_SNIPPETS_PER_USER = getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 10)
|
||||||
|
|
||||||
# Set parent snippet
|
# Set parent snippet
|
||||||
if parent:
|
self.instance.parent = parent
|
||||||
self.instance.parent = parent
|
|
||||||
|
|
||||||
# Add expire datestamp. None indicates 'keep forever', use the default
|
# Add expire datestamp. None indicates 'keep forever', use the default
|
||||||
# null state of the db column for that.
|
# null state of the db column for that.
|
||||||
|
self.instance.expires = self.cleaned_data['expires']
|
||||||
self.instance.expire_type = self.cleaned_data['expire_type']
|
self.instance.expire_type = self.cleaned_data['expire_type']
|
||||||
|
|
||||||
expires = self.cleaned_data['expires']
|
|
||||||
if expires:
|
|
||||||
self.instance.expires = datetime.datetime.now() + \
|
|
||||||
datetime.timedelta(seconds=int(expires))
|
|
||||||
|
|
||||||
# Save snippet in the db
|
# Save snippet in the db
|
||||||
super(SnippetForm, self).save(*args, **kwargs)
|
super(SnippetForm, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from ..models import Snippet
|
from ..models import Snippet
|
||||||
|
|
||||||
|
@ -133,3 +134,53 @@ class SnippetAPITestCase(TestCase):
|
||||||
response = self.client.post(self.api_url, data)
|
response = self.client.post(self.api_url, data)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
self.assertEqual(Snippet.objects.count(), 0)
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_expire_choices_none_given(self):
|
||||||
|
# No expire choice given will set a default expiration of one month
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
||||||
|
def test_expire_choices_invalid_given(self):
|
||||||
|
# A expire choice that does not exist returns a BadRequest
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'foobar'})
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 0)
|
||||||
|
|
||||||
|
def test_valid_expiration_choices(self):
|
||||||
|
"""
|
||||||
|
Test all the different expiration choices. We dont actually test
|
||||||
|
the deletion, since thats handled in the `test_snippet` section.
|
||||||
|
"""
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'onetime'})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_ONETIME)
|
||||||
|
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'never'})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 2)
|
||||||
|
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_KEEP)
|
||||||
|
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 3)
|
||||||
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 7})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 4)
|
||||||
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
||||||
|
response = self.client.post(self.api_url, {
|
||||||
|
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 30})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Snippet.objects.count(), 5)
|
||||||
|
self.assertTrue(Snippet.objects.all()[0].expires)
|
||||||
|
|
|
@ -340,14 +340,10 @@ class SnippetTestCase(TestCase):
|
||||||
Snippets without an expiration date wont get deleted automatically.
|
Snippets without an expiration date wont get deleted automatically.
|
||||||
"""
|
"""
|
||||||
data = self.valid_form_data()
|
data = self.valid_form_data()
|
||||||
|
data['expires'] = 'never'
|
||||||
self.client.post(self.new_url, data, follow=True)
|
self.client.post(self.new_url, data, follow=True)
|
||||||
|
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
s = Snippet.objects.all()[0]
|
|
||||||
s.expires = None
|
|
||||||
s.save()
|
|
||||||
|
|
||||||
management.call_command('cleanup_snippets')
|
management.call_command('cleanup_snippets')
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ 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 django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from dpaste.forms import SnippetForm
|
from dpaste.forms import SnippetForm, get_expire_values, EXPIRE_CHOICES
|
||||||
from dpaste.models import Snippet, ONETIME_LIMIT
|
from dpaste.models import Snippet, ONETIME_LIMIT
|
||||||
from dpaste.highlight import LEXER_WORDWRAP, LEXER_LIST
|
from dpaste.highlight import LEXER_WORDWRAP, LEXER_LIST
|
||||||
from dpaste.highlight import LEXER_DEFAULT, LEXER_KEYS
|
from dpaste.highlight import LEXER_DEFAULT, LEXER_KEYS
|
||||||
|
@ -285,6 +285,7 @@ FORMAT_MAPPING = {
|
||||||
def snippet_api(request):
|
def snippet_api(request):
|
||||||
content = request.POST.get('content', '').strip()
|
content = request.POST.get('content', '').strip()
|
||||||
lexer = request.REQUEST.get('lexer', LEXER_DEFAULT).strip()
|
lexer = request.REQUEST.get('lexer', LEXER_DEFAULT).strip()
|
||||||
|
expires = request.REQUEST.get('expires', '').strip()
|
||||||
format = request.REQUEST.get('format', 'default').strip()
|
format = request.REQUEST.get('format', 'default').strip()
|
||||||
|
|
||||||
if not content:
|
if not content:
|
||||||
|
@ -294,10 +295,21 @@ def snippet_api(request):
|
||||||
return HttpResponseBadRequest('Invalid lexer given. Valid lexers are: %s' %
|
return HttpResponseBadRequest('Invalid lexer given. Valid lexers are: %s' %
|
||||||
', '.join(LEXER_KEYS))
|
', '.join(LEXER_KEYS))
|
||||||
|
|
||||||
|
if expires:
|
||||||
|
expire_options = [str(i) for i in dict(EXPIRE_CHOICES).keys()]
|
||||||
|
if not expires in expire_options:
|
||||||
|
return HttpResponseBadRequest('Invalid expire choice "{}" given. '
|
||||||
|
'Valid values are: {}'.format(expires, ', '.join(expire_options)))
|
||||||
|
expires, expire_type = get_expire_values(expires)
|
||||||
|
else:
|
||||||
|
expires = datetime.datetime.now() + datetime.timedelta(seconds=60 * 60 * 24 * 30)
|
||||||
|
expire_type = Snippet.EXPIRE_TIME
|
||||||
|
|
||||||
s = Snippet.objects.create(
|
s = Snippet.objects.create(
|
||||||
content=content,
|
content=content,
|
||||||
lexer=lexer,
|
lexer=lexer,
|
||||||
expires=datetime.datetime.now()+datetime.timedelta(seconds=60*60*24*30)
|
expires=expires,
|
||||||
|
expire_type=expire_type,
|
||||||
)
|
)
|
||||||
s.save()
|
s.save()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue