1from logging import getLogger 2from random import SystemRandom 3 4from django.apps import apps 5from django.db import models 6from django.urls import reverse 7from django.utils.translation import ugettext_lazy as _ 8from six import python_2_unicode_compatible 9 10from dpaste import highlight 11 12config = apps.get_app_config('dpaste') 13logger = getLogger(__file__) 14R = SystemRandom() 15 16 17def generate_secret_id(length): 18 if length > config.SLUG_LENGTH: 19 logger.warning( 20 'Slug creation triggered a duplicate, ' 21 'consider increasing the SLUG_LENGTH.' 22 ) 23 24 secret_id = ''.join( 25 [ 26 R.choice(config.SLUG_CHOICES) 27 for i in range(length or config.SLUG_LENGTH) 28 ] 29 ) 30 31 # Check if this slug already exists, if not, return this new slug 32 try: 33 Snippet.objects.get(secret_id=secret_id) 34 except Snippet.DoesNotExist: 35 return secret_id 36 37 # Otherwise create a new slug which is +1 character longer 38 # than the previous one. 39 return generate_secret_id(length=length + 1) 40 41 42@python_2_unicode_compatible 43class Snippet(models.Model): 44 EXPIRE_TIME = 1 45 EXPIRE_KEEP = 2 46 EXPIRE_ONETIME = 3 47 EXPIRE_CHOICES = ( 48 (EXPIRE_TIME, _('Expire by timestamp')), 49 (EXPIRE_KEEP, _('Keep Forever')), 50 (EXPIRE_ONETIME, _('One-Time snippet')), 51 ) 52 53 secret_id = models.CharField( 54 _('Secret ID'), max_length=255, blank=True, null=True, unique=True 55 ) 56 content = models.TextField(_('Content')) 57 lexer = models.CharField( 58 _('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT 59 ) 60 published = models.DateTimeField(_('Published'), auto_now_add=True) 61 expire_type = models.PositiveSmallIntegerField( 62 _('Expire Type'), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][0] 63 ) 64 expires = models.DateTimeField(_('Expires'), blank=True, null=True) 65 view_count = models.PositiveIntegerField(_('View count'), default=0) 66 rtl = models.BooleanField(_('Right-to-left'), default=False) 67 parent = models.ForeignKey( 68 'self', 69 null=True, 70 blank=True, 71 verbose_name=_('Parent Snippet'), 72 related_name='children', 73 on_delete=models.CASCADE, 74 ) 75 76 class Meta: 77 ordering = ('-published',) 78 db_table = 'dpaste_snippet' 79 80 def __str__(self): 81 return self.secret_id 82 83 def save(self, *args, **kwargs): 84 if not self.secret_id: 85 self.secret_id = generate_secret_id(length=config.SLUG_LENGTH) 86 super(Snippet, self).save(*args, **kwargs) 87 88 def get_absolute_url(self): 89 return reverse('snippet_details', kwargs={'snippet_id': self.secret_id}) 90 91 def highlight(self): 92 HighlighterClass = highlight.get_highlighter_class(self.lexer) 93 return HighlighterClass().render( 94 code_string=self.content, 95 lexer_name=self.lexer, 96 direction='rtl' if self.rtl else 'ltr', 97 ) 98 99 @property 100 def lexer_name(self): 101 """Display name for this lexer.""" 102 return highlight.Highlighter.get_lexer_display_name(self.lexer) 103 104 @property 105 def remaining_views(self): 106 if self.expire_type == self.EXPIRE_ONETIME: 107 remaining = config.ONETIME_LIMIT - self.view_count 108 return remaining > 0 and remaining or 0 109