mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 16:12:51 +11:00
Added option to keep snippets forever.
This commit is contained in:
parent
25a83cf0f8
commit
964e1b64c7
10 changed files with 110 additions and 12 deletions
|
@ -1,6 +1,11 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
2.4 (dev)
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* Added an option to keep snippets forever
|
||||||
|
|
||||||
2.3 (2014-01-07)
|
2.3 (2014-01-07)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ possible to be installed into an existing Django project like a regular app.
|
||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 1
|
||||||
|
|
||||||
testing
|
testing
|
||||||
integration
|
integration
|
||||||
|
|
|
@ -35,6 +35,9 @@ Finally just ``syncdb`` or if you use South, migrate::
|
||||||
|
|
||||||
manage.py migrate dpaste
|
manage.py migrate dpaste
|
||||||
|
|
||||||
|
Purge expired snippets
|
||||||
|
======================
|
||||||
|
|
||||||
Do not forget to setup a cron job to purge expired snippets. You need to
|
Do not forget to setup a cron job to purge expired snippets. You need to
|
||||||
run the management command ``cleanup_snippets``. A cron job I use looks like::
|
run the management command ``cleanup_snippets``. A cron job I use looks like::
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,15 @@ behavior without touching the code:
|
||||||
(3600 * 24 * 30 * 12 * 100, ugettext(u'100 Years')),
|
(3600 * 24 * 30 * 12 * 100, ugettext(u'100 Years')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
You can keep snippets forever when you set the choice key to ``never``.
|
||||||
|
The management command will ignore these snippets::
|
||||||
|
|
||||||
|
ugettext = lambda s: s
|
||||||
|
DPASTE_EXPIRE_CHOICES = (
|
||||||
|
(3600, ugettext(u'In one hour')),
|
||||||
|
(u'never', ugettext(u'Never')),
|
||||||
|
)
|
||||||
|
|
||||||
``DPASTE_EXPIRE_DEFAULT``
|
``DPASTE_EXPIRE_DEFAULT``
|
||||||
The key of the default value of ``DPASTE_EXPIRE_CHOICES``. Default:
|
The key of the default value of ``DPASTE_EXPIRE_CHOICES``. Default:
|
||||||
``3600 * 24 * 30 * 12 * 100`` or simpler: ``DPASTE_EXPIRE_CHOICES[2][0]``.
|
``3600 * 24 * 30 * 12 * 100`` or simpler: ``DPASTE_EXPIRE_CHOICES[2][0]``.
|
||||||
|
|
|
@ -61,7 +61,6 @@ class SnippetForm(forms.ModelForm):
|
||||||
if 'l' in request.GET and request.GET['l'] in LEXER_KEYS:
|
if 'l' in request.GET and request.GET['l'] in LEXER_KEYS:
|
||||||
self.fields['lexer'].initial = request.GET['l']
|
self.fields['lexer'].initial = request.GET['l']
|
||||||
|
|
||||||
|
|
||||||
def clean_content(self):
|
def clean_content(self):
|
||||||
content = self.cleaned_data.get('content', '')
|
content = self.cleaned_data.get('content', '')
|
||||||
if content.strip() == '':
|
if content.strip() == '':
|
||||||
|
@ -75,6 +74,12 @@ class SnippetForm(forms.ModelForm):
|
||||||
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_expire_options(self):
|
||||||
|
expires = self.cleaned_data['expire_options']
|
||||||
|
if expires == u'never':
|
||||||
|
return None
|
||||||
|
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', 15)
|
MAX_SNIPPETS_PER_USER = getattr(settings, 'DPASTE_MAX_SNIPPETS_PER_USER', 15)
|
||||||
|
|
||||||
|
@ -82,9 +87,12 @@ class SnippetForm(forms.ModelForm):
|
||||||
if parent:
|
if parent:
|
||||||
self.instance.parent = parent
|
self.instance.parent = parent
|
||||||
|
|
||||||
# Add expire datestamp
|
# Add expire datestamp. None indicates 'keep forever', use the default
|
||||||
self.instance.expires = datetime.datetime.now() + \
|
# null state of the db column for that.
|
||||||
datetime.timedelta(seconds=int(self.cleaned_data['expire_options']))
|
expires = self.cleaned_data['expire_options']
|
||||||
|
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)
|
||||||
|
|
|
@ -12,7 +12,10 @@ class Command(LabelCommand):
|
||||||
help = "Purges snippets that are expired"
|
help = "Purges snippets that are expired"
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
deleteable_snippets = Snippet.objects.filter(expires__lte=datetime.datetime.now())
|
deleteable_snippets = Snippet.objects.filter(
|
||||||
|
expires__isnull=False,
|
||||||
|
expires__lte=datetime.datetime.now()
|
||||||
|
)
|
||||||
sys.stdout.write(u"%s snippets gets deleted:\n" % deleteable_snippets.count())
|
sys.stdout.write(u"%s snippets gets deleted:\n" % deleteable_snippets.count())
|
||||||
for d in deleteable_snippets:
|
for d in deleteable_snippets:
|
||||||
sys.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires))
|
sys.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires))
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
|
||||||
|
# Changing field 'Snippet.expires'
|
||||||
|
db.alter_column('dpaste_snippet', 'expires', self.gf('django.db.models.fields.DateTimeField')(null=True))
|
||||||
|
|
||||||
|
# Changing field 'Snippet.secret_id'
|
||||||
|
db.alter_column('dpaste_snippet', 'secret_id', self.gf('django.db.models.fields.CharField')(max_length=255, null=True))
|
||||||
|
|
||||||
|
# Changing field 'Snippet.published'
|
||||||
|
db.alter_column('dpaste_snippet', 'published', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True))
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
|
||||||
|
# Changing field 'Snippet.expires'
|
||||||
|
db.alter_column('dpaste_snippet', 'expires', self.gf('django.db.models.fields.DateTimeField')(default=None))
|
||||||
|
|
||||||
|
# Changing field 'Snippet.secret_id'
|
||||||
|
db.alter_column('dpaste_snippet', 'secret_id', self.gf('django.db.models.fields.CharField')(default='', max_length=255))
|
||||||
|
|
||||||
|
# Changing field 'Snippet.published'
|
||||||
|
db.alter_column('dpaste_snippet', 'published', self.gf('django.db.models.fields.DateTimeField')())
|
||||||
|
|
||||||
|
models = {
|
||||||
|
u'dpaste.snippet': {
|
||||||
|
'Meta': {'ordering': "('-published',)", 'object_name': 'Snippet'},
|
||||||
|
'content': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||||
|
'lexer': ('django.db.models.fields.CharField', [], {'default': "'python'", 'max_length': '30'}),
|
||||||
|
u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||||
|
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['dpaste.Snippet']"}),
|
||||||
|
'published': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||||
|
'secret_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||||
|
u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['dpaste']
|
|
@ -18,11 +18,11 @@ def generate_secret_id(length=L, alphabet=T):
|
||||||
return ''.join([R.choice(alphabet) for i in range(length)])
|
return ''.join([R.choice(alphabet) for i in range(length)])
|
||||||
|
|
||||||
class Snippet(models.Model):
|
class Snippet(models.Model):
|
||||||
secret_id = models.CharField(_(u'Secret ID'), max_length=255, blank=True)
|
secret_id = models.CharField(_(u'Secret ID'), max_length=255, blank=True, null=True)
|
||||||
content = models.TextField(_(u'Content'), )
|
content = models.TextField(_(u'Content'))
|
||||||
lexer = models.CharField(_(u'Lexer'), max_length=30, default=LEXER_DEFAULT)
|
lexer = models.CharField(_(u'Lexer'), max_length=30, default=LEXER_DEFAULT)
|
||||||
published = models.DateTimeField(_(u'Published'), blank=True)
|
published = models.DateTimeField(_(u'Published'), auto_now_add=True)
|
||||||
expires = models.DateTimeField(_(u'Expires'), blank=True)
|
expires = models.DateTimeField(_(u'Expires'), blank=True, null=True)
|
||||||
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
|
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -37,8 +37,7 @@ class Snippet(models.Model):
|
||||||
return self.is_root_node() and not self.get_children()
|
return self.is_root_node() and not self.get_children()
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.pk:
|
if not self.secret_id:
|
||||||
self.published = datetime.now()
|
|
||||||
self.secret_id = generate_secret_id()
|
self.secret_id = generate_secret_id()
|
||||||
super(Snippet, self).save(*args, **kwargs)
|
super(Snippet, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -310,6 +310,22 @@ class SnippetTestCase(TestCase):
|
||||||
management.call_command('cleanup_snippets')
|
management.call_command('cleanup_snippets')
|
||||||
self.assertEqual(Snippet.objects.count(), 1)
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
|
def test_delete_management_snippet_that_never_expires_will_not_get_deleted(self):
|
||||||
|
"""
|
||||||
|
Snippets without an expiration date wont get deleted automatically.
|
||||||
|
"""
|
||||||
|
data = self.valid_form_data()
|
||||||
|
self.client.post(self.new_url, data, follow=True)
|
||||||
|
|
||||||
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
|
s = Snippet.objects.all()[0]
|
||||||
|
s.expires = None
|
||||||
|
s.save()
|
||||||
|
|
||||||
|
management.call_command('cleanup_snippets')
|
||||||
|
self.assertEqual(Snippet.objects.count(), 1)
|
||||||
|
|
||||||
def test_highlighting(self):
|
def test_highlighting(self):
|
||||||
# You can pass any lexer to the pygmentize function and it will
|
# You can pass any lexer to the pygmentize function and it will
|
||||||
# never fail loudly.
|
# never fail loudly.
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# These requirements are only required for local testing or development.
|
||||||
|
# To use dpaste it's enough to install the package, all, and only the
|
||||||
|
# necessary dependencies are installed automatically.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
# Project dependencies
|
# Project dependencies
|
||||||
django==1.6.1
|
django==1.6.1
|
||||||
django-mptt==0.6.0
|
django-mptt==0.6.0
|
||||||
|
|
Loading…
Reference in a new issue