snipt/snipts/models.py

350 lines
12 KiB
Python
Raw Normal View History

2015-07-24 18:39:25 -07:00
import datetime
import difflib
2015-07-24 18:39:25 -07:00
import hashlib
import random
import re
2015-07-24 18:39:25 -07:00
from annoying.functions import get_object_or_None
2011-10-02 15:38:20 -07:00
from django.conf import settings
2015-07-24 18:39:25 -07:00
from django.contrib.auth.models import User
from django.db import models
2012-04-23 11:34:21 -07:00
from markdown_deux import markdown
2011-10-02 15:38:20 -07:00
from pygments import highlight
2015-07-24 18:39:25 -07:00
from pygments.formatters import HtmlFormatter
2011-10-02 15:38:20 -07:00
from pygments.lexers import get_lexer_by_name
from pygments.util import ClassNotFound
2012-02-11 07:23:09 -08:00
from snipts.utils import slugify_uniquely
2015-07-24 18:39:25 -07:00
from taggit.managers import TaggableManager
from taggit.utils import edit_string_for_tags
from teams.models import Team
2012-01-29 20:49:14 -08:00
2011-10-02 15:38:20 -07:00
2012-07-18 21:39:43 -07:00
class Snipt(models.Model):
2011-10-01 10:23:05 -07:00
"""An individual Snipt."""
2019-03-11 13:45:49 -07:00
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
2019-01-23 15:52:55 -08:00
last_user_saved = models.ForeignKey(
User,
blank=True,
null=True,
related_name="last_user_saved",
2019-03-11 13:45:49 -07:00
on_delete=models.CASCADE,
2019-01-23 15:52:55 -08:00
)
title = models.CharField(max_length=255, blank=True, null=True, default="Untitled")
2015-07-24 18:28:31 -07:00
slug = models.SlugField(max_length=255, blank=True)
custom_slug = models.SlugField(max_length=255, blank=True)
tags = TaggableManager()
2012-05-27 11:51:21 -07:00
2015-07-24 18:28:31 -07:00
lexer = models.CharField(max_length=50)
code = models.TextField()
meta = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
stylized = models.TextField(blank=True, null=True)
2012-12-27 19:57:03 -08:00
stylized_min = models.TextField(blank=True, null=True)
2015-07-24 18:28:31 -07:00
embedded = models.TextField(blank=True, null=True)
line_count = models.IntegerField(blank=True, null=True, default=None)
2012-05-27 11:51:21 -07:00
2015-07-24 18:28:31 -07:00
key = models.CharField(max_length=100, blank=True, null=True)
public = models.BooleanField(default=False)
2016-05-12 08:47:07 -07:00
secure = models.BooleanField(default=False)
2015-07-24 18:28:31 -07:00
blog_post = models.BooleanField(default=False)
2012-09-17 09:49:55 -07:00
2015-07-24 18:28:31 -07:00
views = models.IntegerField(default=0)
2016-11-29 20:50:32 -08:00
created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True, editable=False)
2012-05-27 11:51:21 -07:00
publish_date = models.DateTimeField(blank=True, null=True)
def _unidiff_output(self, expected, actual):
expected = expected.splitlines(1)
actual = actual.splitlines(1)
diff = difflib.unified_diff(expected, actual)
2019-01-23 15:52:55 -08:00
return "".join(diff)
def __init__(self, *args, **kwargs):
super(Snipt, self).__init__(*args, **kwargs)
self.original_code = self.code
2011-10-01 10:23:05 -07:00
def save(self, *args, **kwargs):
2012-01-29 20:49:14 -08:00
2011-10-01 10:23:05 -07:00
if not self.slug:
2012-02-14 08:39:45 -08:00
self.slug = slugify_uniquely(self.title, Snipt)
2011-10-01 10:23:05 -07:00
2012-04-09 12:19:09 -07:00
if not self.key:
2019-01-23 15:52:55 -08:00
self.key = hashlib.md5(
(
self.slug + str(datetime.datetime.now()) + str(random.random())
).encode("utf-8")
).hexdigest()
2012-04-09 12:19:09 -07:00
2019-01-23 15:52:55 -08:00
if self.lexer == "markdown":
self.stylized = markdown(self.code, "default")
2012-06-11 12:53:56 -07:00
# Snipt embeds
for match in re.findall('\[\[(\w{32})\]\]', self.stylized):
self.stylized = self.stylized.replace('[[' + str(match) + ']]',
"""
2015-07-24 18:28:31 -07:00
<script type="text/javascript"
src="https://snipt.net/embed/{}/?snipt">
2015-07-24 18:28:31 -07:00
</script>
2019-01-23 15:52:55 -08:00
<div id="snipt-embed-{}"></div>""".format(
match, match
),
)
2012-06-11 12:53:56 -07:00
# YouTube embeds
2019-01-23 15:52:55 -08:00
for match in re.findall(
"\[\[youtube-(\w{11})\-(\d+)x(\d+)\]\]", self.stylized
):
self.stylized = self.stylized.replace(
"[[youtube-{}-{}x{}]]".format(
str(match[0]), str(match[1]), str(match[2])
),
"""<iframe width="{}" height="{}"
2015-07-24 18:28:31 -07:00
src="https://www.youtube.com/embed/{}"
2019-01-23 15:52:55 -08:00
frameborder="0" allowfullscreen></iframe>""".format(
match[1], match[2], match[0]
),
)
2012-06-11 12:53:56 -07:00
2012-08-13 07:21:50 -07:00
# Vimeo embeds
2019-01-23 15:52:55 -08:00
for match in re.findall("\[\[vimeo-(\d+)\-(\d+)x(\d+)\]\]", self.stylized):
self.stylized = self.stylized.replace(
"[[vimeo-{}-{}x{}]]".format(
str(match[0]), str(match[1]), str(match[2])
),
"""<iframe src="https://player.vimeo.com/video/{}"
2015-07-24 18:28:31 -07:00
width="{}" height="{}" frameborder="0"
webkitAllowFullScreen mozallowfullscreen
2019-01-23 15:52:55 -08:00
allowFullScreen></iframe>""".format(
match[0], match[1], match[2]
),
)
2012-08-13 07:21:50 -07:00
2013-04-02 21:07:54 -07:00
# Tweet embeds
2019-01-23 15:52:55 -08:00
for match in re.findall("\[\[tweet-(\d+)\]\]", self.stylized):
self.stylized = self.stylized.replace(
"[[tweet-{}]]".format(str(match)),
'<div class="embedded-tweet" data-tweet-id="{}"></div>'.format(
str(match)
),
)
2013-04-02 21:07:54 -07:00
# Parse Snipt usernames
for match in re.findall('@(\w+) ', self.stylized):
# Try and get the Snipt user by username.
user = get_object_or_None(User, username=match)
if user:
2013-04-05 07:22:14 -07:00
url = user.profile.get_user_profile_url()
2019-01-23 15:52:55 -08:00
self.stylized = self.stylized.replace(
"@{} ".format(str(match)),
'<a href="{}">@{}</a> '.format(url, match),
)
2012-04-23 11:34:21 -07:00
else:
2019-01-23 15:52:55 -08:00
self.stylized = highlight(
self.code,
get_lexer_by_name(self.lexer, encoding="UTF-8"),
HtmlFormatter(
linenos="table", anchorlinenos=True, lineanchors="L", linespans="L"
),
)
self.line_count = len(self.code.split("\n"))
if self.lexer == "markdown":
lexer_for_embedded = "text"
2012-04-23 11:34:21 -07:00
else:
lexer_for_embedded = self.lexer
2019-01-23 15:52:55 -08:00
embedded = highlight(
self.code,
get_lexer_by_name(lexer_for_embedded, encoding="UTF-8"),
HtmlFormatter(
style="native",
noclasses=True,
prestyles="""
2012-02-26 19:20:37 -08:00
background-color: #1C1C1C;
border-radius: 5px;
color: #D0D0D0;
display: block;
2012-07-18 17:17:34 -07:00
font: 11px Monaco, monospace;
2012-02-26 19:20:37 -08:00
margin: 0;
overflow: auto;
padding: 15px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
2019-01-23 15:52:55 -08:00
""",
),
)
embedded = (
embedded.replace('\\"', '\\\\"')
.replace("'", "\\'")
.replace("\\", "\\\\")
.replace("background: #202020", "")
)
2012-02-26 19:20:37 -08:00
self.embedded = embedded
snipt = super(Snipt, self).save(*args, **kwargs)
2019-01-23 15:52:55 -08:00
diff = self._unidiff_output(self.original_code or "", self.code)
2015-09-24 13:50:36 -07:00
2019-01-23 15:52:55 -08:00
if diff != "":
log_entry = SniptLogEntry(
user=self.last_user_saved, snipt=self, code=self.code, diff=diff
)
2015-09-24 13:50:36 -07:00
log_entry.save()
return snipt
2011-10-01 10:23:05 -07:00
def __unicode__(self):
2011-10-01 10:23:05 -07:00
return self.title
2011-06-05 08:55:27 -07:00
2012-09-17 10:26:54 -07:00
def favs(self):
return Favorite.objects.filter(snipt=self).count()
2012-12-27 19:57:03 -08:00
def get_stylized_min(self):
if self.stylized_min is None:
2019-01-23 15:52:55 -08:00
if self.lexer == "markdown":
self.stylized_min = markdown(self.code[:1000], "default")
2012-12-27 19:57:03 -08:00
else:
2015-07-24 18:28:31 -07:00
self.stylized_min = highlight(
self.code[:1000],
2019-01-23 15:52:55 -08:00
get_lexer_by_name(self.lexer, encoding="UTF-8"),
HtmlFormatter(linenos="table", linenospecial=1, lineanchors="line"),
)
2012-12-27 19:57:03 -08:00
return self.stylized_min
2011-10-01 16:09:59 -07:00
def get_absolute_url(self):
2012-05-03 19:19:05 -07:00
2012-06-01 18:05:25 -07:00
if self.blog_post:
2013-08-13 11:20:46 -07:00
if self.user.profile.blog_domain:
2019-01-23 15:52:55 -08:00
return u"http://{}/{}/".format(
self.user.profile.blog_domain.split(" ")[0], self.slug
)
2012-06-04 12:58:03 -07:00
else:
return u'https://{}.snipt.net/{}/'.format(
self.user.username.replace('_', '-'), self.slug)
2012-06-01 18:05:25 -07:00
2012-06-04 17:57:20 -07:00
if self.custom_slug:
2019-01-23 15:52:55 -08:00
return u"/{}/".format(self.custom_slug)
2012-06-04 17:57:20 -07:00
if self.public:
2019-01-23 15:52:55 -08:00
return u"/{}/{}/".format(self.user.username, self.slug)
else:
2019-01-23 15:52:55 -08:00
return u"/{}/{}/?key={}".format(self.user.username, self.slug, self.key)
2011-10-01 16:09:59 -07:00
2012-01-16 21:07:15 -08:00
def get_full_absolute_url(self):
2012-06-04 17:57:20 -07:00
if self.blog_post:
2013-08-13 11:20:46 -07:00
if self.user.profile.blog_domain:
2019-01-23 15:52:55 -08:00
return u"http://{}/{}/".format(
self.user.profile.blog_domain.split(" ")[0], self.slug
)
2012-06-04 17:57:20 -07:00
else:
return u'https://{}.snipt.net/{}/'.format(
self.user.username, self.slug)
2012-06-04 17:57:20 -07:00
2012-06-23 19:55:52 -07:00
if self.public:
2019-01-23 15:52:55 -08:00
return u"/{}/{}/".format(self.user.username, self.slug)
2012-06-23 19:55:52 -07:00
else:
2019-01-23 15:52:55 -08:00
return u"/{}/{}/?key={}".format(self.user.username, self.slug, self.key)
2012-01-16 21:07:15 -08:00
def get_download_url(self):
try:
lexer_obj = get_lexer_by_name(self.lexer)
except ClassNotFound:
lexer_obj = None
if lexer_obj and lexer_obj.filenames:
2019-01-23 15:52:55 -08:00
filename = lexer_obj.filenames[0].replace("*", self.slug)
else:
2019-01-23 15:52:55 -08:00
if self.lexer == "markdown":
filename = u"{}.md".format(self.slug)
else:
2019-01-23 15:52:55 -08:00
filename = u"{}.txt".format(self.slug)
2019-01-23 15:52:55 -08:00
return u"/download/{}/{}".format(self.key, filename)
2011-10-23 20:30:57 -07:00
def get_embed_url(self):
2013-03-15 11:38:21 -07:00
if settings.DEBUG:
root = 'http://local.snipt.net'
2013-03-15 11:38:21 -07:00
else:
root = 'https://snipt.net'
2013-03-15 11:38:21 -07:00
2019-01-23 15:52:55 -08:00
return "{}/embed/{}/".format(root, self.key)
2011-10-02 15:38:20 -07:00
2013-03-15 11:19:28 -07:00
def get_raw_url(self):
2019-01-23 15:52:55 -08:00
return "/raw/{}/".format(self.key)
2013-03-15 11:19:28 -07:00
2011-11-10 11:34:51 -08:00
@property
def sorted_tags(self):
2019-01-23 15:52:55 -08:00
return self.tags.all().order_by("name")
2011-11-10 11:34:51 -08:00
2012-02-17 16:14:53 -08:00
@property
def tags_list(self):
return edit_string_for_tags(self.tags.all())
2011-10-13 10:30:44 -07:00
@property
def lexer_name(self):
2019-01-23 15:52:55 -08:00
if self.lexer == "markdown":
return "Markdown"
2012-04-23 11:34:21 -07:00
else:
return get_lexer_by_name(self.lexer).name
2012-02-13 19:36:59 -08:00
2015-10-18 07:35:44 -07:00
def is_authorized_user(self, user):
if self.user == user:
return True
if self.user.profile.is_a_team:
team = Team.objects.get(user=self.user, disabled=False)
return team.user_is_member(user)
return False
2015-10-18 07:35:44 -07:00
2015-07-24 18:28:31 -07:00
class SniptLogEntry(models.Model):
"""An individual log entry for a Snipt changeset."""
2019-03-11 13:45:49 -07:00
user = models.ForeignKey(User, on_delete=models.CASCADE)
snipt = models.ForeignKey(Snipt, on_delete=models.CASCADE)
code = models.TextField()
diff = models.TextField()
created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True, editable=False)
@property
def snipt_name(self):
2019-01-23 15:52:55 -08:00
return self.snipt.title or "Untitled"
2016-05-12 08:47:07 -07:00
class SniptSecureView(models.Model):
"""A single view to a secure snipt."""
2016-05-12 08:47:07 -07:00
2019-03-11 13:45:49 -07:00
user = models.ForeignKey(User, on_delete=models.CASCADE)
snipt = models.ForeignKey(Snipt, on_delete=models.CASCADE)
2016-05-12 08:47:07 -07:00
created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True, editable=False)
@property
def snipt_name(self):
2019-01-23 15:52:55 -08:00
return self.snipt.title or "Untitled"
2016-05-12 08:47:07 -07:00
2012-07-18 21:39:43 -07:00
class Favorite(models.Model):
2019-03-11 13:45:49 -07:00
snipt = models.ForeignKey(Snipt, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
2012-02-13 19:36:59 -08:00
2015-07-24 18:28:31 -07:00
created = models.DateTimeField(auto_now_add=True, editable=False)
2012-04-07 21:52:10 -07:00
modified = models.DateTimeField(auto_now=True, editable=False)
2015-07-24 18:28:31 -07:00
2012-02-13 19:36:59 -08:00
def __unicode__(self):
2019-01-23 15:52:55 -08:00
return u"{} favorited by {}".format(self.snipt.title, self.user.username)