Browse Source

Black.

master
Nick Sergeant 2 years ago
parent
commit
39403a600c
49 changed files with 1474 additions and 1179 deletions
  1. +4
    -4
      accounts/admin.py
  2. +2
    -2
      accounts/management/commands/migrate_user_passwords.py
  3. +106
    -27
      accounts/migrations/0001_initial.py
  4. +4
    -6
      accounts/migrations/0002_auto_20150724_2010.py
  5. +45
    -15
      accounts/migrations/0003_auto_20160512_1058.py
  6. +52
    -53
      accounts/models.py
  7. +2
    -2
      accounts/urls.py
  8. +4
    -6
      accounts/views.py
  9. +25
    -25
      blogs/middleware.py
  10. +1
    -1
      blogs/urls.py
  11. +92
    -79
      blogs/views.py
  12. +96
    -98
      settings.py
  13. +27
    -14
      snipts/admin.py
  14. +217
    -186
      snipts/api.py
  15. +21
    -14
      snipts/management/commands/import_snipts.py
  16. +69
    -32
      snipts/migrations/0001_initial.py
  17. +18
    -10
      snipts/migrations/0002_sniptlogentry.py
  18. +10
    -5
      snipts/migrations/0003_snipt_last_user_saved.py
  19. +7
    -9
      snipts/migrations/0004_auto_20160512_1058.py
  20. +16
    -8
      snipts/migrations/0005_sniptsecureview.py
  21. +128
    -116
      snipts/models.py
  22. +5
    -6
      snipts/search_indexes.py
  23. +13
    -13
      snipts/templatetags/snipt_tags.py
  24. +56
    -50
      snipts/tests.py
  25. +30
    -39
      snipts/urls.py
  26. +7
    -5
      snipts/utils.py
  27. +135
    -127
      snipts/views.py
  28. +3
    -2
      teams/admin.py
  29. +29
    -13
      teams/migrations/0001_initial.py
  30. +5
    -7
      teams/migrations/0002_team_email.py
  31. +7
    -7
      teams/migrations/0003_auto_20150818_0057.py
  32. +7
    -7
      teams/migrations/0004_auto_20150930_1526.py
  33. +4
    -8
      teams/migrations/0005_auto_20150930_2124.py
  34. +18
    -7
      teams/migrations/0006_team_plan.py
  35. +3
    -7
      teams/migrations/0007_team_disabled.py
  36. +20
    -7
      teams/migrations/0008_auto_20151018_2053.py
  37. +20
    -7
      teams/migrations/0009_auto_20160512_1058.py
  38. +31
    -24
      teams/models.py
  39. +14
    -12
      teams/urls.py
  40. +18
    -23
      teams/views.py
  41. +42
    -36
      urls.py
  42. +14
    -5
      user-admin/admin.py
  43. +3
    -3
      utils/backends.py
  44. +14
    -12
      utils/forms.py
  45. +7
    -8
      utils/templatetags/pygmentize.py
  46. +1
    -1
      utils/templatetags/truncate_lines.py
  47. +6
    -7
      utils/templatetags/verbatim.py
  48. +2
    -1
      utils/views.py
  49. +14
    -23
      views.py

+ 4
- 4
accounts/admin.py View File

@@ -3,9 +3,9 @@ from django.contrib import admin


class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'is_pro', 'stripe_id', 'gittip_username',
'teams_beta_seen')
list_filter = ['teams_beta_seen', 'teams_beta_applied']
search_fields = ('user__username', 'gittip_username',)
list_display = ("user", "is_pro", "stripe_id", "gittip_username", "teams_beta_seen")
list_filter = ["teams_beta_seen", "teams_beta_applied"]
search_fields = ("user__username", "gittip_username")

admin.site.register(UserProfile, UserProfileAdmin)

+ 2
- 2
accounts/management/commands/migrate_user_passwords.py View File

@@ -14,9 +14,9 @@ class Command(BaseCommand):
self.stdout.write(u"Updating %s user passwords..." % users.count())

for user in users:
if user.password[0:3] == 'bc$':
if user.password[0:3] == "bc$":
pw = user.password
new_password = pw[0:3].replace('bc$', 'bcrypt$') + pw[3:]
new_password = pw[0:3].replace("bc$", "bcrypt$") + pw[3:]
user.password = new_password
user.save()



+ 106
- 27
accounts/migrations/0001_initial.py View File

@@ -7,36 +7,115 @@ from django.conf import settings

class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]

operations = [
migrations.CreateModel(
name='UserProfile',
name="UserProfile",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('is_pro', models.BooleanField(default=False)),
('teams_beta_seen', models.BooleanField(default=False)),
('teams_beta_applied', models.BooleanField(default=False)),
('pro_date', models.DateTimeField(null=True, blank=True)),
('stripe_id', models.CharField(max_length=100, null=True, blank=True)),
('has_gravatar', models.BooleanField(default=False)),
('list_view', models.CharField(default=b'N', max_length=1, choices=[(b'N', b'Normal'), (b'C', b'Compact')])),
('blog_title', models.CharField(max_length=250, null=True, blank=True)),
('blog_theme', models.CharField(default=b'A', max_length=1, choices=[(b'D', b'Default'), (b'A', b'Pro Adams')])),
('blog_domain', models.CharField(max_length=250, null=True, blank=True)),
('default_editor', models.CharField(default=b'C', max_length=250, choices=[(b'C', b'CodeMirror'), (b'T', b'Textarea')])),
('editor_theme', models.CharField(default=b'default', max_length=250, choices=[(b'default', b'Default'), (b'ambiance', b'Ambiance'), (b'blackboard', b'Blackboard'), (b'cobalt', b'Cobalt'), (b'eclipse', b'Eclipse'), (b'elegant', b'Elegant'), (b'erlang-dark', b'Erlang Dark'), (b'lesser-dark', b'Lesser Dark'), (b'monokai', b'Monokai'), (b'neat', b'Neat'), (b'night', b'Night'), (b'rubyblue', b'Ruby Blue'), (b'solarized dark', b'Solarized Dark'), (b'solarized light', b'Solarized Light'), (b'twilight', b'Twilight'), (b'vibrant-ink', b'Vibrant Ink'), (b'xq-dark', b'XQ Dark')])),
('gittip_username', models.CharField(max_length=250, null=True, blank=True)),
('disqus_shortname', models.CharField(max_length=250, null=True, blank=True)),
('google_analytics_tracking_id', models.CharField(max_length=250, null=True, blank=True)),
('gauges_site_id', models.CharField(max_length=250, null=True, blank=True)),
('google_ad_client', models.CharField(max_length=250, null=True, blank=True)),
('google_ad_slot', models.CharField(max_length=250, null=True, blank=True)),
('google_ad_width', models.CharField(max_length=250, null=True, blank=True)),
('google_ad_height', models.CharField(max_length=250, null=True, blank=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, unique=True)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("is_pro", models.BooleanField(default=False)),
("teams_beta_seen", models.BooleanField(default=False)),
("teams_beta_applied", models.BooleanField(default=False)),
("pro_date", models.DateTimeField(null=True, blank=True)),
("stripe_id", models.CharField(max_length=100, null=True, blank=True)),
("has_gravatar", models.BooleanField(default=False)),
(
"list_view",
models.CharField(
default=b"N",
max_length=1,
choices=[(b"N", b"Normal"), (b"C", b"Compact")],
),
),
("blog_title", models.CharField(max_length=250, null=True, blank=True)),
(
"blog_theme",
models.CharField(
default=b"A",
max_length=1,
choices=[(b"D", b"Default"), (b"A", b"Pro Adams")],
),
),
(
"blog_domain",
models.CharField(max_length=250, null=True, blank=True),
),
(
"default_editor",
models.CharField(
default=b"C",
max_length=250,
choices=[(b"C", b"CodeMirror"), (b"T", b"Textarea")],
),
),
(
"editor_theme",
models.CharField(
default=b"default",
max_length=250,
choices=[
(b"default", b"Default"),
(b"ambiance", b"Ambiance"),
(b"blackboard", b"Blackboard"),
(b"cobalt", b"Cobalt"),
(b"eclipse", b"Eclipse"),
(b"elegant", b"Elegant"),
(b"erlang-dark", b"Erlang Dark"),
(b"lesser-dark", b"Lesser Dark"),
(b"monokai", b"Monokai"),
(b"neat", b"Neat"),
(b"night", b"Night"),
(b"rubyblue", b"Ruby Blue"),
(b"solarized dark", b"Solarized Dark"),
(b"solarized light", b"Solarized Light"),
(b"twilight", b"Twilight"),
(b"vibrant-ink", b"Vibrant Ink"),
(b"xq-dark", b"XQ Dark"),
],
),
),
(
"gittip_username",
models.CharField(max_length=250, null=True, blank=True),
),
(
"disqus_shortname",
models.CharField(max_length=250, null=True, blank=True),
),
(
"google_analytics_tracking_id",
models.CharField(max_length=250, null=True, blank=True),
),
(
"gauges_site_id",
models.CharField(max_length=250, null=True, blank=True),
),
(
"google_ad_client",
models.CharField(max_length=250, null=True, blank=True),
),
(
"google_ad_slot",
models.CharField(max_length=250, null=True, blank=True),
),
(
"google_ad_width",
models.CharField(max_length=250, null=True, blank=True),
),
(
"google_ad_height",
models.CharField(max_length=250, null=True, blank=True),
),
("user", models.ForeignKey(to=settings.AUTH_USER_MODEL, unique=True)),
],
),
)
]

+ 4
- 6
accounts/migrations/0002_auto_20150724_2010.py View File

@@ -7,14 +7,12 @@ from django.conf import settings

class Migration(migrations.Migration):

dependencies = [
('accounts', '0001_initial'),
]
dependencies = [("accounts", "0001_initial")]

operations = [
migrations.AlterField(
model_name='userprofile',
name='user',
model_name="userprofile",
name="user",
field=models.OneToOneField(to=settings.AUTH_USER_MODEL),
),
)
]

+ 45
- 15
accounts/migrations/0003_auto_20160512_1058.py View File

@@ -6,29 +6,59 @@ from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
('accounts', '0002_auto_20150724_2010'),
]
dependencies = [("accounts", "0002_auto_20150724_2010")]

operations = [
migrations.AlterField(
model_name='userprofile',
name='blog_theme',
field=models.CharField(max_length=1, choices=[('D', 'Default'), ('A', 'Pro Adams')], default='A'),
model_name="userprofile",
name="blog_theme",
field=models.CharField(
max_length=1,
choices=[("D", "Default"), ("A", "Pro Adams")],
default="A",
),
),
migrations.AlterField(
model_name='userprofile',
name='default_editor',
field=models.CharField(max_length=250, choices=[('C', 'CodeMirror'), ('T', 'Textarea')], default='C'),
model_name="userprofile",
name="default_editor",
field=models.CharField(
max_length=250,
choices=[("C", "CodeMirror"), ("T", "Textarea")],
default="C",
),
),
migrations.AlterField(
model_name='userprofile',
name='editor_theme',
field=models.CharField(max_length=250, choices=[('default', 'Default'), ('ambiance', 'Ambiance'), ('blackboard', 'Blackboard'), ('cobalt', 'Cobalt'), ('eclipse', 'Eclipse'), ('elegant', 'Elegant'), ('erlang-dark', 'Erlang Dark'), ('lesser-dark', 'Lesser Dark'), ('monokai', 'Monokai'), ('neat', 'Neat'), ('night', 'Night'), ('rubyblue', 'Ruby Blue'), ('solarized dark', 'Solarized Dark'), ('solarized light', 'Solarized Light'), ('twilight', 'Twilight'), ('vibrant-ink', 'Vibrant Ink'), ('xq-dark', 'XQ Dark')], default='default'),
model_name="userprofile",
name="editor_theme",
field=models.CharField(
max_length=250,
choices=[
("default", "Default"),
("ambiance", "Ambiance"),
("blackboard", "Blackboard"),
("cobalt", "Cobalt"),
("eclipse", "Eclipse"),
("elegant", "Elegant"),
("erlang-dark", "Erlang Dark"),
("lesser-dark", "Lesser Dark"),
("monokai", "Monokai"),
("neat", "Neat"),
("night", "Night"),
("rubyblue", "Ruby Blue"),
("solarized dark", "Solarized Dark"),
("solarized light", "Solarized Light"),
("twilight", "Twilight"),
("vibrant-ink", "Vibrant Ink"),
("xq-dark", "XQ Dark"),
],
default="default",
),
),
migrations.AlterField(
model_name='userprofile',
name='list_view',
field=models.CharField(max_length=1, choices=[('N', 'Normal'), ('C', 'Compact')], default='N'),
model_name="userprofile",
name="list_view",
field=models.CharField(
max_length=1, choices=[("N", "Normal"), ("C", "Compact")], default="N"
),
),
]

+ 52
- 53
accounts/models.py View File

@@ -9,39 +9,30 @@ from teams.models import Team

class UserProfile(models.Model):

LIST_VIEW_CHOICES = (
('N', 'Normal'),
('C', 'Compact'),
)
LIST_VIEW_CHOICES = (("N", "Normal"), ("C", "Compact"))

EDITOR_CHOICES = (
('C', 'CodeMirror'),
('T', 'Textarea'),
)
EDITOR_CHOICES = (("C", "CodeMirror"), ("T", "Textarea"))

THEME_CHOICES = (
('D', 'Default'),
('A', 'Pro Adams'),
)
THEME_CHOICES = (("D", "Default"), ("A", "Pro Adams"))

EDITOR_THEME_CHOICES = (
('default', 'Default'),
('ambiance', 'Ambiance'),
('blackboard', 'Blackboard'),
('cobalt', 'Cobalt'),
('eclipse', 'Eclipse'),
('elegant', 'Elegant'),
('erlang-dark', 'Erlang Dark'),
('lesser-dark', 'Lesser Dark'),
('monokai', 'Monokai'),
('neat', 'Neat'),
('night', 'Night'),
('rubyblue', 'Ruby Blue'),
('solarized dark', 'Solarized Dark'),
('solarized light', 'Solarized Light'),
('twilight', 'Twilight'),
('vibrant-ink', 'Vibrant Ink'),
('xq-dark', 'XQ Dark'),
("default", "Default"),
("ambiance", "Ambiance"),
("blackboard", "Blackboard"),
("cobalt", "Cobalt"),
("eclipse", "Eclipse"),
("elegant", "Elegant"),
("erlang-dark", "Erlang Dark"),
("lesser-dark", "Lesser Dark"),
("monokai", "Monokai"),
("neat", "Neat"),
("night", "Night"),
("rubyblue", "Ruby Blue"),
("solarized dark", "Solarized Dark"),
("solarized light", "Solarized Light"),
("twilight", "Twilight"),
("vibrant-ink", "Vibrant Ink"),
("xq-dark", "XQ Dark"),
)

# User
@@ -52,27 +43,35 @@ class UserProfile(models.Model):
pro_date = models.DateTimeField(blank=True, null=True)
stripe_id = models.CharField(max_length=100, null=True, blank=True)
has_gravatar = models.BooleanField(default=False)
list_view = models.CharField(max_length=1, null=False, blank=False,
default='N', choices=LIST_VIEW_CHOICES)
list_view = models.CharField(
max_length=1, null=False, blank=False, default="N", choices=LIST_VIEW_CHOICES
)

# Blog
blog_title = models.CharField(max_length=250, null=True, blank=True)
blog_theme = models.CharField(max_length=1, null=False, blank=False,
default='A', choices=THEME_CHOICES)
blog_theme = models.CharField(
max_length=1, null=False, blank=False, default="A", choices=THEME_CHOICES
)
blog_domain = models.CharField(max_length=250, null=True, blank=True)

# Editor
default_editor = models.CharField(max_length=250, null=False, blank=False,
default='C', choices=EDITOR_CHOICES)
editor_theme = models.CharField(max_length=250, null=False, blank=False,
default='default',
choices=EDITOR_THEME_CHOICES)
default_editor = models.CharField(
max_length=250, null=False, blank=False, default="C", choices=EDITOR_CHOICES
)
editor_theme = models.CharField(
max_length=250,
null=False,
blank=False,
default="default",
choices=EDITOR_THEME_CHOICES,
)

# Services and Analytics
gittip_username = models.CharField(max_length=250, null=True, blank=True)
disqus_shortname = models.CharField(max_length=250, null=True, blank=True)
google_analytics_tracking_id = models.CharField(max_length=250, null=True,
blank=True)
google_analytics_tracking_id = models.CharField(
max_length=250, null=True, blank=True
)
gauges_site_id = models.CharField(max_length=250, null=True, blank=True)

# Google Ads
@@ -82,36 +81,34 @@ class UserProfile(models.Model):
google_ad_height = models.CharField(max_length=250, null=True, blank=True)

def get_blog_posts(self):
return Snipt.objects.filter(user=self.user, blog_post=True,
public=True)
return Snipt.objects.filter(user=self.user, blog_post=True, public=True)

def get_primary_blog_domain(self):
if not self.blog_domain:
return None
else:
return self.blog_domain.split(' ')[0]
return self.blog_domain.split(" ")[0]

def get_user_profile_url(self):

# If the user has a blog domain, use that.
if self.blog_domain:
url = 'http://{}'.format(self.get_primary_blog_domain())
url = "http://{}".format(self.get_primary_blog_domain())

# Otherwise, if they have blog posts, use their Snipt blog URL.
elif self.get_blog_posts():
url = 'https://{}.snippets.siftie.com/'.format(self.user.username)
url = "https://{}.snippets.siftie.com/".format(self.user.username)

# Otherwise, use their regular Snipt profile page.
else:
url = 'https://snippets.siftie.com/{}/'.format(self.user.username)
url = "https://snippets.siftie.com/{}/".format(self.user.username)

return url

def has_public_snipts(self):
return True \
if Snipt.objects.filter(user=self,
public=True).count() > 0 \
else False
return (
True if Snipt.objects.filter(user=self, public=True).count() > 0 else False
)

@property
def is_a_team(self):
@@ -127,14 +124,16 @@ class UserProfile(models.Model):

@property
def has_teams(self):
if (len(self.teams()) > 0):
if len(self.teams()) > 0:
return True
else:
return False

def get_account_age(self):
delta = datetime.now().replace(tzinfo=None) - \
self.user.date_joined.replace(tzinfo=None)
delta = datetime.now().replace(tzinfo=None) - self.user.date_joined.replace(
tzinfo=None
)
return delta.days


User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

+ 2
- 2
accounts/urls.py View File

@@ -3,6 +3,6 @@ from django.conf.urls import url


urlpatterns = [
url(r'^stats/$', views.stats, name='account-stats'),
url(r'^', views.account, name='account-detail')
url(r"^stats/$", views.stats, name="account-stats"),
url(r"^", views.account, name="account-detail"),
]

+ 4
- 6
accounts/views.py View File

@@ -5,17 +5,15 @@ from snipts.models import Snipt


@login_required
@render_to('account.html')
@render_to("account.html")
def account(request):
return {}


@login_required
@render_to('stats.html')
@render_to("stats.html")
def stats(request):

snipts = Snipt.objects.filter(user=request.user).order_by('-views')
snipts = Snipt.objects.filter(user=request.user).order_by("-views")

return {
'snipts': snipts
}
return {"snipts": snipts}

+ 25
- 25
blogs/middleware.py View File

@@ -8,43 +8,43 @@ class BlogMiddleware:
def process_request(self, request):
request.blog_user = None

host = request.META.get('HTTP_HOST', '')
host_s = host.replace('www.', '').split('.')

if host != 'snippets.siftie.com' and \
host != 'snipt.localhost' and \
host != 'local.snippets.siftie.com':
host = request.META.get("HTTP_HOST", "")
host_s = host.replace("www.", "").split(".")

if (
host != "snippets.siftie.com"
and host != "snipt.localhost"
and host != "local.snippets.siftie.com"
):
if len(host_s) > 2:
if host_s[1] == 'snipt':
if host_s[1] == "snipt":

blog_user = ''.join(host_s[:-2])
blog_user = "".join(host_s[:-2])

if '-' in blog_user:
request.blog_user = \
get_object_or_None(User,
username__iexact=blog_user)
if "-" in blog_user:
request.blog_user = get_object_or_None(
User, username__iexact=blog_user
)

if request.blog_user is None:
request.blog_user = \
get_object_or_404(User,
username__iexact=blog_user
.replace('-', '_'))
request.blog_user = get_object_or_404(
User, username__iexact=blog_user.replace("-", "_")
)
else:
request.blog_user = \
get_object_or_404(User, username__iexact=blog_user)
request.blog_user = get_object_or_404(
User, username__iexact=blog_user
)

if request.blog_user is None:
pro_users = User.objects.filter(userprofile__is_pro=True)

for pro_user in pro_users:
if pro_user.profile.blog_domain:
if host in pro_user.profile.blog_domain.split(' '):
if host in pro_user.profile.blog_domain.split(" "):
request.blog_user = pro_user

if host != \
pro_user.profile.get_primary_blog_domain():
if host != pro_user.profile.get_primary_blog_domain():
return HttpResponseRedirect(
'http://' +
pro_user
.profile
.get_primary_blog_domain())
"http://"
+ pro_user.profile.get_primary_blog_domain()
)

+ 1
- 1
blogs/urls.py View File

@@ -2,4 +2,4 @@ from blogs import views
from django.conf.urls import url


urlpatterns = [url(r'^$', views.blog, name='blog')]
urlpatterns = [url(r"^$", views.blog, name="blog")]

+ 92
- 79
blogs/views.py View File

@@ -4,10 +4,7 @@ from annoying.functions import get_object_or_None
from django.shortcuts import get_object_or_404, render
from snipts.models import Snipt

THEME_CHOICES = {
'D': 'blogs/themes/default/',
'A': 'blogs/themes/pro-adams/',
}
THEME_CHOICES = {"D": "blogs/themes/default/", "A": "blogs/themes/pro-adams/"}


def blog_list(request, username_or_custom_slug=None):
@@ -15,83 +12,95 @@ def blog_list(request, username_or_custom_slug=None):
if username_or_custom_slug:
return blog_post(request, username_or_custom_slug)

snipts = Snipt.objects.filter(user=request.blog_user,
blog_post=True,
public=True,
publish_date__lte=datetime.datetime.now()) \
.order_by('-publish_date') \
.exclude(title__iexact='Homepage') \
.exclude(title__iexact='Work')

normal_snipts = Snipt.objects.filter(blog_post=False,
user=request.blog_user,
public=True) \
.order_by('-created')
normal_snipts = normal_snipts.exclude(title__in=[''])
normal_snipts = normal_snipts.exclude(tags__name__in=['tmp'])
snipts = (
Snipt.objects.filter(
user=request.blog_user,
blog_post=True,
public=True,
publish_date__lte=datetime.datetime.now(),
)
.order_by("-publish_date")
.exclude(title__iexact="Homepage")
.exclude(title__iexact="Work")
)

normal_snipts = Snipt.objects.filter(
blog_post=False, user=request.blog_user, public=True
).order_by("-created")
normal_snipts = normal_snipts.exclude(title__in=[""])
normal_snipts = normal_snipts.exclude(tags__name__in=["tmp"])
normal_snipts = normal_snipts[:3]

sidebar = get_object_or_None(Snipt, user=request.blog_user,
title='Sidebar', blog_post=True)
header = get_object_or_None(Snipt, user=request.blog_user, title='Header',
blog_post=True)
custom_css = get_object_or_None(Snipt, user=request.blog_user, title='CSS',
lexer='css', blog_post=True)
sidebar = get_object_or_None(
Snipt, user=request.blog_user, title="Sidebar", blog_post=True
)
header = get_object_or_None(
Snipt, user=request.blog_user, title="Header", blog_post=True
)
custom_css = get_object_or_None(
Snipt, user=request.blog_user, title="CSS", lexer="css", blog_post=True
)

context = {
'blog_user': request.blog_user,
'custom_css': custom_css,
'has_snipts': True,
'header': header,
'normal_snipts': normal_snipts,
'public': True,
'sidebar': sidebar,
'snipts': snipts,
"blog_user": request.blog_user,
"custom_css": custom_css,
"has_snipts": True,
"header": header,
"normal_snipts": normal_snipts,
"public": True,
"sidebar": sidebar,
"snipts": snipts,
}

if 'rss' in request.GET:
context['snipts'] = context['snipts'][:20]
if "rss" in request.GET:
context["snipts"] = context["snipts"][:20]
return rss(request, context)

template = THEME_CHOICES[request.blog_user.profile.blog_theme]

template = '{}/list.html'.format(template)
template = "{}/list.html".format(template)

return render(
request,
template,
context,
)
return render(request, template, context)


def blog_post(request, username_or_custom_slug):

snipt = get_object_or_404(Snipt, user=request.blog_user,
blog_post=True,
public=True,
publish_date__lte=datetime.datetime.now(),
slug=username_or_custom_slug)

snipts = Snipt.objects.filter(user=request.blog_user,
blog_post=True,
public=True,
publish_date__lte=datetime.datetime.now()) \
.order_by('-publish_date') \
.exclude(title__iexact='Homepage') \
.exclude(title__iexact='Work')

sidebar = get_object_or_None(Snipt, user=request.blog_user,
title='Sidebar', blog_post=True)
header = get_object_or_None(Snipt, user=request.blog_user, title='Header',
blog_post=True)
custom_css = get_object_or_None(Snipt, user=request.blog_user, title='CSS',
lexer='css', blog_post=True)

normal_snipts = Snipt.objects.filter(blog_post=False,
user=request.blog_user,
public=True).order_by('-created')
normal_snipts = normal_snipts.exclude(title__in=[''])
normal_snipts = normal_snipts.exclude(tags__name__in=['tmp'])
snipt = get_object_or_404(
Snipt,
user=request.blog_user,
blog_post=True,
public=True,
publish_date__lte=datetime.datetime.now(),
slug=username_or_custom_slug,
)

snipts = (
Snipt.objects.filter(
user=request.blog_user,
blog_post=True,
public=True,
publish_date__lte=datetime.datetime.now(),
)
.order_by("-publish_date")
.exclude(title__iexact="Homepage")
.exclude(title__iexact="Work")
)

sidebar = get_object_or_None(
Snipt, user=request.blog_user, title="Sidebar", blog_post=True
)
header = get_object_or_None(
Snipt, user=request.blog_user, title="Header", blog_post=True
)
custom_css = get_object_or_None(
Snipt, user=request.blog_user, title="CSS", lexer="css", blog_post=True
)

normal_snipts = Snipt.objects.filter(
blog_post=False, user=request.blog_user, public=True
).order_by("-created")
normal_snipts = normal_snipts.exclude(title__in=[""])
normal_snipts = normal_snipts.exclude(tags__name__in=["tmp"])
normal_snipts = normal_snipts[:3]

if snipt.user != request.user:
@@ -99,25 +108,29 @@ def blog_post(request, username_or_custom_slug):
snipt.save()

context = {
'blog_user': request.blog_user,
'custom_css': custom_css,
'detail': True,
'has_snipts': True,
'header': header,
'normal_snipts': normal_snipts,
'public': True,
'sidebar': sidebar,
'snipt': snipt,
'snipts': snipts,
"blog_user": request.blog_user,
"custom_css": custom_css,
"detail": True,
"has_snipts": True,
"header": header,
"normal_snipts": normal_snipts,
"public": True,
"sidebar": sidebar,
"snipt": snipt,
"snipts": snipts,
}

template = THEME_CHOICES[request.blog_user.profile.blog_theme]

template = '{}/post.html'.format(template)
template = "{}/post.html".format(template)

return render(request, template, context)


def rss(request, context):
return render(request, 'blogs/themes/default/rss.xml', context,
content_type="application/rss+xml")
return render(
request,
"blogs/themes/default/rss.xml",
context,
content_type="application/rss+xml",
)

+ 96
- 98
settings.py View File

@@ -3,134 +3,132 @@ from urllib.parse import urlparse
import dj_database_url
import os

if 'DATABASE_URL' in os.environ:
DATABASES = {'default': dj_database_url.config()}
if "DATABASE_URL" in os.environ:
DATABASES = {"default": dj_database_url.config()}

ABSOLUTE_URL_OVERRIDES = {'auth.user': lambda u: "/%s/" % u.username}
ABSOLUTE_URL_OVERRIDES = {"auth.user": lambda u: "/%s/" % u.username}
ACCOUNT_ACTIVATION_DAYS = 0
ADMINS = (('Siftie', 'team@siftie.com'),)
ALLOWED_HOSTS = ['*']
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
AUTHENTICATION_BACKENDS = ('utils.backends.EmailOrUsernameModelBackend',)
ADMINS = (("Siftie", "team@siftie.com"),)
ALLOWED_HOSTS = ["*"]
AUTH_PROFILE_MODULE = "accounts.UserProfile"
AUTHENTICATION_BACKENDS = ("utils.backends.EmailOrUsernameModelBackend",)
BASE_PATH = os.path.dirname(__file__)
CSRF_COOKIE_SECURE = True if 'USE_SSL' in os.environ else False
CSRF_COOKIE_SECURE = True if "USE_SSL" in os.environ else False
CORS_ORIGIN_ALLOW_ALL = True
DEBUG = True if 'DEBUG' in os.environ else False
DEFAULT_FROM_EMAIL = os.environ.get('POSTMARK_EMAIL', 'support@siftie.com')
EMAIL_BACKEND = 'postmark.django_backend.EmailBackend'
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
INTERNAL_IPS = ('127.0.0.1',)
LANGUAGE_CODE = 'en-us'
LOGIN_REDIRECT_URL = '/login-redirect/'
LOGIN_URL = '/login/'
LOGOUT_URL = '/logout/'
DEBUG = True if "DEBUG" in os.environ else False
DEFAULT_FROM_EMAIL = os.environ.get("POSTMARK_EMAIL", "support@siftie.com")
EMAIL_BACKEND = "postmark.django_backend.EmailBackend"
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor"
INTERNAL_IPS = ("127.0.0.1",)
LANGUAGE_CODE = "en-us"
LOGIN_REDIRECT_URL = "/login-redirect/"
LOGIN_URL = "/login/"
LOGOUT_URL = "/logout/"
MANAGERS = ADMINS
MEDIA_ROOT = os.path.join(BASE_PATH, 'media/uploads')
MEDIA_URL = '/media/uploads/'
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
MEDIA_ROOT = os.path.join(BASE_PATH, "media/uploads")
MEDIA_URL = "/media/uploads/"
MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
"django.contrib.auth.hashers.BCryptPasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.SHA1PasswordHasher",
"django.contrib.auth.hashers.MD5PasswordHasher",
"django.contrib.auth.hashers.CryptPasswordHasher",
)
POSTMARK_API_KEY = os.environ.get('POSTMARK_API_KEY', '')
POSTMARK_API_KEY = os.environ.get("POSTMARK_API_KEY", "")
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
REGISTRATION_EMAIL_HTML = False
ROOT_URLCONF = 'urls'
SECRET_KEY = os.environ.get('SECRET_KEY', 'changeme')
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True if 'USE_SSL' in os.environ else False
ROOT_URLCONF = "urls"
SECRET_KEY = os.environ.get("SECRET_KEY", "changeme")
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SECURE_SSL_REDIRECT = True if "USE_SSL" in os.environ else False
SEND_BROKEN_LINK_EMAILS = False
SERVER_EMAIL = os.environ.get('POSTMARK_EMAIL', 'support@siftie.com')
SERVER_EMAIL = os.environ.get("POSTMARK_EMAIL", "support@siftie.com")
SESSION_COOKIE_AGE = 15801100
SESSION_COOKIE_SECURE = True if 'USE_SSL' in os.environ else False
SESSION_COOKIE_SECURE = True if "USE_SSL" in os.environ else False
SITE_ID = 1
STATICFILES_DIRS = (os.path.join(BASE_PATH, 'media'),)
STATICFILES_FINDERS = ('django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder')
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_PATH, 'static')
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_PATH, "media"),)
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
)
STATICFILES_STORAGE = "whitenoise.django.GzipManifestStaticFilesStorage"
STATIC_ROOT = os.path.join(BASE_PATH, "static")
STATIC_URL = "/static/"
TASTYPIE_CANNED_ERROR = """There was an error with your request. The site
developers have a record of this error, please email support@siftie.com and
we'll help you out."""

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(PROJECT_PATH, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(PROJECT_PATH, "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.template.context_processors.static",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
},
},
}
]

TIME_ZONE = 'America/New_York'
USE_HTTPS = True if 'USE_SSL' in os.environ else False
TIME_ZONE = "America/New_York"
USE_HTTPS = True if "USE_SSL" in os.environ else False
USE_I18N = True
USE_L10N = True
USE_TZ = True

INSTALLED_APPS = (
'accounts',
'blogs',
'corsheaders',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.humanize',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.staticfiles',
'django_extensions',
'gunicorn',
'haystack',
'markdown_deux',
'pagination',
'postmark',
'registration',
'snipts',
'storages',
'taggit',
'tastypie',
'teams',
'user-admin',
'utils',
"accounts",
"blogs",
"corsheaders",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.humanize",
"django.contrib.messages",
"django.contrib.sessions",
"django.contrib.sites",
"django.contrib.staticfiles",
"django_extensions",
"gunicorn",
"haystack",
"markdown_deux",
"pagination",
"postmark",
"registration",
"snipts",
"storages",
"taggit",
"tastypie",
"teams",
"user-admin",
"utils",
)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {},
'loggers': {}
"version": 1,
"disable_existing_loggers": False,
"filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
"handlers": {},
"loggers": {},
}
MIDDLEWARE_CLASSES = (
'django.middleware.security.SecurityMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'pagination.middleware.PaginationMiddleware',
'blogs.middleware.BlogMiddleware',
"django.middleware.security.SecurityMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"pagination.middleware.PaginationMiddleware",
"blogs.middleware.BlogMiddleware",
)

try:


+ 27
- 14
snipts/admin.py View File

@@ -3,29 +3,42 @@ from snipts.models import Favorite, Snipt, SniptLogEntry


class SniptAdmin(admin.ModelAdmin):
readonly_fields = ('last_user_saved', 'user',)
list_display = ('title', 'slug', 'views', 'favs', 'user', 'lexer',
'public', 'blog_post', 'created', 'modified',
'publish_date')
list_filter = ('blog_post',)
search_fields = ('title', 'slug', 'user__username', 'lexer', 'id', 'key',)
ordering = ('-created',)
prepopulated_fields = {'slug': ('title',)}
readonly_fields = ("last_user_saved", "user")
list_display = (
"title",
"slug",
"views",
"favs",
"user",
"lexer",
"public",
"blog_post",
"created",
"modified",
"publish_date",
)
list_filter = ("blog_post",)
search_fields = ("title", "slug", "user__username", "lexer", "id", "key")
ordering = ("-created",)
prepopulated_fields = {"slug": ("title",)}


admin.site.register(Snipt, SniptAdmin)


class SniptLogEntryAdmin(admin.ModelAdmin):
readonly_fields = ('snipt', 'user',)
list_display = ('snipt_name', 'user', 'created', 'modified')
readonly_fields = ("snipt", "user")
list_display = ("snipt_name", "user", "created", "modified")


admin.site.register(SniptLogEntry, SniptLogEntryAdmin)


class FavoriteAdmin(admin.ModelAdmin):
readonly_fields = ('snipt', 'user',)
list_display = ('snipt', 'user', 'created',)
search_fields = ('snipt', 'user',)
ordering = ('-created',)
readonly_fields = ("snipt", "user")
list_display = ("snipt", "user", "created")
search_fields = ("snipt", "user")
ordering = ("-created",)


admin.site.register(Favorite, FavoriteAdmin)

+ 217
- 186
snipts/api.py View File

@@ -139,11 +139,10 @@ class PrivateUserAuthorization(Authorization):
class FavoriteValidation(Validation):
def is_valid(self, bundle, request=None):
errors = {}
snipt = bundle.data['snipt']
snipt = bundle.data["snipt"]

if Favorite.objects.filter(user=bundle.request.user,
snipt=snipt).count():
errors = 'User has already favorited this snipt.'
if Favorite.objects.filter(user=bundle.request.user, snipt=snipt).count():
errors = "User has already favorited this snipt."

return errors

@@ -152,8 +151,8 @@ class SniptValidation(Validation):
def is_valid(self, bundle, request=None):
errors = {}

if (len(bundle.data['title']) > 255):
errors = 'Title must be 255 characters or less.'
if len(bundle.data["title"]) > 255:
errors = "Title must be 255 characters or less."

return errors

@@ -164,10 +163,12 @@ class UserProfileValidation(Validation):

for field in bundle.data:
if bundle.data[field]:
if not re.match('^[ A-Za-z0-9\/\@\._-]*$', bundle.data[field]):
errors[field] = ('Only spaces, letters, numbers, '
'underscores, dashes, periods, forward '
'slashes, and "at sign" are valid.')
if not re.match("^[ A-Za-z0-9\/\@\._-]*$", bundle.data[field]):
errors[field] = (
"Only spaces, letters, numbers, "
"underscores, dashes, periods, forward "
'slashes, and "at sign" are valid.'
)

return errors

@@ -175,33 +176,33 @@ class UserProfileValidation(Validation):
class PublicUserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'user'
fields = ['id', 'username']
resource_name = "user"
fields = ["id", "username"]
include_absolute_url = True
allowed_methods = ['get']
filtering = {'username': ['contains', 'exact']}
allowed_methods = ["get"]
filtering = {"username": ["contains", "exact"]}
max_limit = 200
cache = SimpleCache()

def dehydrate(self, bundle):
bundle.data['snipts'] = '/api/public/snipt/?user=%d' % bundle.obj.id
bundle.data['email_md5'] = hashlib \
.md5(bundle.obj.email.lower().encode('utf-8')) \
.hexdigest()
bundle.data['snipts_count'] = Snipt.objects.filter(user=bundle.obj.id,
public=True).count()
bundle.data["snipts"] = "/api/public/snipt/?user=%d" % bundle.obj.id
bundle.data["email_md5"] = hashlib.md5(
bundle.obj.email.lower().encode("utf-8")
).hexdigest()
bundle.data["snipts_count"] = Snipt.objects.filter(
user=bundle.obj.id, public=True
).count()
return bundle


class PublicTagResource(ModelResource):
class Meta:
queryset = Tag.objects.filter()
queryset = queryset.annotate(
count=models.Count('taggit_taggeditem_items__id'))
queryset = queryset.order_by('-count', 'name')
resource_name = 'tag'
fields = ['id', 'name']
allowed_methods = ['get']
queryset = queryset.annotate(count=models.Count("taggit_taggeditem_items__id"))
queryset = queryset.order_by("-count", "name")
resource_name = "tag"
fields = ["id", "name"]
allowed_methods = ["get"]
max_limit = 200
cache = SimpleCache()

@@ -211,60 +212,74 @@ class PublicTagResource(ModelResource):

orm_filters = super(PublicTagResource, self).build_filters(filters)

if 'q' in filters:
orm_filters['slug'] = filters['q']
if "q" in filters:
orm_filters["slug"] = filters["q"]

return orm_filters

def dehydrate(self, bundle):
bundle.data['absolute_url'] = '/public/tag/%s/' % bundle.obj.slug
bundle.data['snipts'] = '/api/public/snipt/?tag=%d' % bundle.obj.id
bundle.data["absolute_url"] = "/public/tag/%s/" % bundle.obj.slug
bundle.data["snipts"] = "/api/public/snipt/?tag=%d" % bundle.obj.id
return bundle


class PublicSniptResource(ModelResource):
user = fields.ForeignKey(PublicUserResource, 'user', full=True)
tags = fields.ToManyField(PublicTagResource, 'tags', related_name='tag',
full=True)
user = fields.ForeignKey(PublicUserResource, "user", full=True)
tags = fields.ToManyField(PublicTagResource, "tags", related_name="tag", full=True)

class Meta:
queryset = Snipt.objects.filter(public=True).order_by('-created')
resource_name = 'snipt'
fields = ['id', 'title', 'slug', 'lexer', 'code', 'description',
'line_count', 'stylized', 'created', 'modified',
'publish_date', 'blog_post', 'meta']
queryset = Snipt.objects.filter(public=True).order_by("-created")
resource_name = "snipt"
fields = [
"id",
"title",
"slug",
"lexer",
"code",
"description",
"line_count",
"stylized",
"created",
"modified",
"publish_date",
"blog_post",
"meta",
]
include_absolute_url = True
allowed_methods = ['get']
filtering = {'user': 'exact', 'blog_post': 'exact'}
ordering = ['created', 'modified']
allowed_methods = ["get"]
filtering = {"user": "exact", "blog_post": "exact"}
ordering = ["created", "modified"]
max_limit = 200
cache = SimpleCache()

def dehydrate(self, bundle):
bundle.data['embed_url'] = bundle.obj.get_embed_url()
bundle.data['raw_url'] = bundle.obj.get_raw_url()
bundle.data['full_absolute_url'] = bundle.obj.get_full_absolute_url()
bundle.data['description_rendered'] = \
linebreaksbr(urlize(bundle.obj.description))
bundle.data["embed_url"] = bundle.obj.get_embed_url()
bundle.data["raw_url"] = bundle.obj.get_raw_url()
bundle.data["full_absolute_url"] = bundle.obj.get_full_absolute_url()
bundle.data["description_rendered"] = linebreaksbr(
urlize(bundle.obj.description)
)

log_entries = bundle.obj.sniptlogentry_set.all()
bundle_log_entries = []

for entry in log_entries:
bundle_log_entries.append({
'created': entry.created,
'user': entry.user,
'code': entry.code,
'diff': entry.diff
})
bundle_log_entries.append(
{
"created": entry.created,
"user": entry.user,
"code": entry.code,
"diff": entry.diff,
}
)

bundle.data['log_entries'] = bundle_log_entries
bundle.data["log_entries"] = bundle_log_entries

if 'omit_code' in bundle.request.GET:
del bundle.data['code']
if "omit_code" in bundle.request.GET:
del bundle.data["code"]

if 'omit_stylized' in bundle.request.GET:
del bundle.data['stylized']
if "omit_stylized" in bundle.request.GET:
del bundle.data["stylized"]

return bundle

@@ -274,14 +289,14 @@ class PublicSniptResource(ModelResource):

orm_filters = super(PublicSniptResource, self).build_filters(filters)

if 'tag' in filters:
tag = Tag.objects.get(pk=filters['tag'])
if "tag" in filters:
tag = Tag.objects.get(pk=filters["tag"])
tagged_items = tag.taggit_taggeditem_items.all()
orm_filters['pk__in'] = [i.object_id for i in tagged_items]
orm_filters["pk__in"] = [i.object_id for i in tagged_items]

if 'q' in filters:
sqs = SearchQuerySet().auto_query(filters['q'])
orm_filters['pk__in'] = [i.pk for i in sqs]
if "q" in filters:
sqs = SearchQuerySet().auto_query(filters["q"])
orm_filters["pk__in"] = [i.pk for i in sqs]

return orm_filters

@@ -289,11 +304,11 @@ class PublicSniptResource(ModelResource):
class PrivateUserProfileResource(ModelResource):
class Meta:
queryset = UserProfile.objects.all()
resource_name = 'profile'
excludes = ['is_pro']
resource_name = "profile"
excludes = ["is_pro"]
validation = UserProfileValidation()
include_absolute_url = False
allowed_methods = ['get', 'put']
allowed_methods = ["get", "put"]
list_allowed_methods = []
authentication = ApiKeyAuthentication()
authorization = PrivateUserProfileAuthorization()
@@ -301,23 +316,22 @@ class PrivateUserProfileResource(ModelResource):
max_limit = 200

def dehydrate(self, bundle):
bundle.data['email'] = bundle.obj.user.email
bundle.data['username'] = bundle.obj.user.username
bundle.data['user_id'] = bundle.obj.user.id
bundle.data['api_key'] = bundle.obj.user.api_key.key
bundle.data["email"] = bundle.obj.user.email
bundle.data["username"] = bundle.obj.user.username
bundle.data["user_id"] = bundle.obj.user.id
bundle.data["api_key"] = bundle.obj.user.api_key.key
return bundle


class PrivateUserResource(ModelResource):
profile = fields.ForeignKey(PrivateUserProfileResource, 'profile',
full=False)
profile = fields.ForeignKey(PrivateUserProfileResource, "profile", full=False)

class Meta:
queryset = User.objects.all()
resource_name = 'user'
fields = ['id', 'username', 'email']
resource_name = "user"
fields = ["id", "username", "email"]
include_absolute_url = True
allowed_methods = ['get']
allowed_methods = ["get"]
list_allowed_methods = []
authentication = ApiKeyAuthentication()
authorization = PrivateUserAuthorization()
@@ -326,155 +340,172 @@ class PrivateUserResource(ModelResource):
cache = SimpleCache()

def dehydrate(self, bundle):
bundle.data['email_md5'] = hashlib \
.md5(bundle.obj.email.lower().encode('utf-8')) \
.hexdigest()
bundle.data['stats'] = {
'public_snipts': Snipt.objects.filter(user=bundle.obj.id,
public=True).count(),
'private_snipts': Snipt.objects.filter(user=bundle.obj.id,
public=False).count(),
'total_snipts': Snipt.objects.filter(user=bundle.obj.id).count(),
'total_views': Snipt.objects.filter(user=bundle.obj.id).aggregate(
models.Sum('views'))['views__sum']
bundle.data["email_md5"] = hashlib.md5(
bundle.obj.email.lower().encode("utf-8")
).hexdigest()
bundle.data["stats"] = {
"public_snipts": Snipt.objects.filter(
user=bundle.obj.id, public=True
).count(),
"private_snipts": Snipt.objects.filter(
user=bundle.obj.id, public=False
).count(),
"total_snipts": Snipt.objects.filter(user=bundle.obj.id).count(),
"total_views": Snipt.objects.filter(user=bundle.obj.id).aggregate(
models.Sum("views")
)["views__sum"],
}

user_snipts = Snipt.objects.filter(user=bundle.obj)
user_tags = [
snipt['tags'] for snipt in user_snipts.values('tags').distinct()
]
user_tags = [snipt["tags"] for snipt in user_snipts.values("tags").distinct()]

tags = [
tag['name'] for tag in
Tag.objects.filter(id__in=user_tags).values('name').distinct()
tag["name"]
for tag in Tag.objects.filter(id__in=user_tags).values("name").distinct()
]

bundle.data['tags'] = tags
bundle.data["tags"] = tags

bundle.data['lexers'] = [
snipt['lexer'] for snipt in user_snipts
.values('lexer').distinct()]
bundle.data["lexers"] = [
snipt["lexer"] for snipt in user_snipts.values("lexer").distinct()
]

return bundle


class PrivateSniptResource(ModelResource):
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
last_user_saved = fields.ForeignKey(PrivateUserResource,
'last_user_saved',
null=True,
full=False)
user = fields.ForeignKey(PrivateUserResource, "user", full=True)
last_user_saved = fields.ForeignKey(
PrivateUserResource, "last_user_saved", null=True, full=False
)
tags_list = ListField()
tags = fields.ToManyField(PublicTagResource, 'tags', related_name='tag',
full=True)
tags = fields.ToManyField(PublicTagResource, "tags", related_name="tag", full=True)

class Meta:
queryset = Snipt.objects.all().order_by('-created')
resource_name = 'snipt'
fields = ['id', 'title', 'slug', 'lexer', 'code', 'description',
'line_count', 'stylized', 'key', 'public', 'secure',
'blog_post', 'created', 'modified', 'publish_date', 'meta']
queryset = Snipt.objects.all().order_by("-created")
resource_name = "snipt"
fields = [
"id",
"title",
"slug",
"lexer",
"code",
"description",
"line_count",
"stylized",
"key",
"public",
"secure",
"blog_post",
"created",
"modified",
"publish_date",
"meta",
]
include_absolute_url = True
detail_allowed_methods = ['get', 'patch', 'put', 'delete']
list_allowed_methods = ['get', 'post']
detail_allowed_methods = ["get", "patch", "put", "delete"]
list_allowed_methods = ["get", "post"]
authentication = ApiKeyAuthentication()
authorization = PrivateSniptAuthorization()
validation = SniptValidation()
ordering = ['created', 'modified']
ordering = ["created", "modified"]
always_return_data = True
max_limit = 200
cache = SimpleCache()

def dehydrate(self, bundle):
bundle.data['embed_url'] = bundle.obj.get_embed_url()
bundle.data['raw_url'] = bundle.obj.get_raw_url()
bundle.data['tags_list'] = edit_string_for_tags(bundle.obj.tags.all())
bundle.data['full_absolute_url'] = bundle.obj.get_full_absolute_url()
bundle.data['description_rendered'] = \
linebreaksbr(urlize(bundle.obj.description))
bundle.data['views'] = bundle.obj.views
bundle.data['favs'] = bundle.obj.favs()

if bundle.data['publish_date']:
bundle.data['publish_date'] = \
date(bundle.data['publish_date'], 'M d, Y \\a\\t h:i A')
bundle.data["embed_url"] = bundle.obj.get_embed_url()
bundle.data["raw_url"] = bundle.obj.get_raw_url()
bundle.data["tags_list"] = edit_string_for_tags(bundle.obj.tags.all())
bundle.data["full_absolute_url"] = bundle.obj.get_full_absolute_url()
bundle.data["description_rendered"] = linebreaksbr(
urlize(bundle.obj.description)
)
bundle.data["views"] = bundle.obj.views
bundle.data["favs"] = bundle.obj.favs()

if bundle.data["publish_date"]:
bundle.data["publish_date"] = date(
bundle.data["publish_date"], "M d, Y \\a\\t h:i A"
)

log_entries = bundle.obj.sniptlogentry_set.all()
bundle_log_entries = []

for entry in log_entries:
bundle_log_entries.append({
'created': entry.created,
'user': entry.user,
'code': entry.code,
'diff': entry.diff
})
bundle_log_entries.append(
{
"created": entry.created,
"user": entry.user,
"code": entry.code,
"diff": entry.diff,
}
)

bundle.data['log_entries'] = bundle_log_entries
bundle.data["log_entries"] = bundle_log_entries

return bundle

def obj_create(self, bundle, **kwargs):
bundle.data['last_user_saved'] = bundle.request.user
bundle.data['tags_list'] = bundle.data.get('tags')
bundle.data['tags'] = []

if 'intended_user' in bundle.data:
bundle.data['user'] = \
User.objects.get(username=bundle.data['intended_user'])
bundle.data["last_user_saved"] = bundle.request.user
bundle.data["tags_list"] = bundle.data.get("tags")
bundle.data["tags"] = []

if "intended_user" in bundle.data:
bundle.data["user"] = User.objects.get(
username=bundle.data["intended_user"]
)
else:
bundle.data['user'] = bundle.request.user
bundle.data["user"] = bundle.request.user

if 'blog_post' in bundle.data:
if "blog_post" in bundle.data:
bundle = self._clean_publish_date(bundle)

return super(PrivateSniptResource, self) \
.obj_create(bundle, **kwargs)
return super(PrivateSniptResource, self).obj_create(bundle, **kwargs)

def obj_update(self, bundle, **kwargs):

instance = Snipt.objects.get(pk=bundle.data['id'])
instance = Snipt.objects.get(pk=bundle.data["id"])

if (instance.user.profile.is_a_team):
if instance.user.profile.is_a_team:
user = instance.user
else:
user = bundle.request.user

bundle.data['created'] = None
bundle.data['last_user_saved'] = bundle.request.user
bundle.data['modified'] = None
bundle.data['user'] = user
bundle.data["created"] = None
bundle.data["last_user_saved"] = bundle.request.user
bundle.data["modified"] = None
bundle.data["user"] = user

if type(bundle.data['tags']) == str or type(bundle.data['tags']) == unicode:
bundle.data['tags_list'] = bundle.data['tags']
if type(bundle.data["tags"]) == str or type(bundle.data["tags"]) == unicode:
bundle.data["tags_list"] = bundle.data["tags"]
else:
bundle.data['tags_list'] = ''
bundle.data['tags'] = ''
bundle.data["tags_list"] = ""
bundle.data["tags"] = ""

if 'blog_post' in bundle.data:
if "blog_post" in bundle.data:
bundle = self._clean_publish_date(bundle)

return super(PrivateSniptResource, self) \
.obj_update(bundle, **kwargs)
return super(PrivateSniptResource, self).obj_update(bundle, **kwargs)

def _clean_publish_date(self, bundle):
if bundle.data['blog_post'] and 'publish_date' not in bundle.data:
bundle.data['publish_date'] = datetime.datetime.now()
elif bundle.data['publish_date'] == '':
bundle.data['publish_date'] = datetime.datetime.now()
elif bundle.data['blog_post']:
if bundle.data["blog_post"] and "publish_date" not in bundle.data:
bundle.data["publish_date"] = datetime.datetime.now()
elif bundle.data["publish_date"] == "":
bundle.data["publish_date"] = datetime.datetime.now()
elif bundle.data["blog_post"]:
c = pdt.Constants()
p = pdt.Calendar(c)
publish_date, result = p.parse(bundle.data['publish_date'])
publish_date, result = p.parse(bundle.data["publish_date"])

if result != 0:
publish_date = time.strftime('%Y-%m-%d %H:%M:%S', publish_date)
publish_date = time.strftime("%Y-%m-%d %H:%M:%S", publish_date)
else:
publish_date = datetime.datetime.now()

bundle.data['publish_date'] = publish_date
elif not bundle.data['blog_post']:
bundle.data['publish_date'] = None
bundle.data["publish_date"] = publish_date
elif not bundle.data["blog_post"]:
bundle.data["publish_date"] = None

return bundle

@@ -484,51 +515,51 @@ class PrivateSniptResource(ModelResource):

orm_filters = super(PrivateSniptResource, self).build_filters(filters)

if 'tag' in filters:
tag = Tag.objects.get(pk=filters['tag'])
if "tag" in filters:
tag = Tag.objects.get(pk=filters["tag"])
tagged_items = tag.taggit_taggeditem_items.all()
orm_filters['pk__in'] = [i.object_id for i in tagged_items]
orm_filters["pk__in"] = [i.object_id for i in tagged_items]

if 'q' in filters:
user = User.objects.get(username=filters['username'])
sqs = SearchQuerySet().filter(author=user, content=filters['q'])
orm_filters['pk__in'] = [i.pk for i in sqs]
if "q" in filters:
user = User.objects.get(username=filters["username"])
sqs = SearchQuerySet().filter(author=user, content=filters["q"])
orm_filters["pk__in"] = [i.pk for i in sqs]

return orm_filters

def save_m2m(self, bundle):
tags = bundle.data.get('tags_list', [])
if tags != '':
tags = bundle.data.get("tags_list", [])
if tags != "":
bundle.obj.tags.set(*parse_tags(tags))
else:
bundle.obj.tags.set()


class PrivateFavoriteResource(ModelResource):
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
snipt = fields.ForeignKey(PrivateSniptResource, 'snipt', full=False)
user = fields.ForeignKey(PrivateUserResource, "user", full=True)
snipt = fields.ForeignKey(PrivateSniptResource, "snipt", full=False)

class Meta:
queryset = Favorite.objects.all().order_by('-created')
resource_name = 'favorite'
fields = ['id']
queryset = Favorite.objects.all().order_by("-created")
resource_name = "favorite"
fields = ["id"]
validation = FavoriteValidation()
detail_allowed_methods = ['get', 'post', 'delete']
list_allowed_methods = ['get', 'post']
detail_allowed_methods = ["get", "post", "delete"]
list_allowed_methods = ["get", "post"]
authentication = ApiKeyAuthentication()
authorization = PrivateFavoriteAuthorization()
ordering = ['created']
ordering = ["created"]
always_return_data = True
max_limit = 200
cache = SimpleCache()

def dehydrate(self, bundle):
bundle.data['snipt'] = '/api/public/snipt/{}/'.format(
bundle.obj.snipt.pk)
bundle.data["snipt"] = "/api/public/snipt/{}/".format(bundle.obj.snipt.pk)
return bundle

def obj_create(self, bundle, **kwargs):
bundle.data['user'] = bundle.request.user
bundle.data['snipt'] = Snipt.objects.get(pk=bundle.data['snipt'])
return super(PrivateFavoriteResource, self) \
.obj_create(bundle, user=bundle.request.user, **kwargs)
bundle.data["user"] = bundle.request.user
bundle.data["snipt"] = Snipt.objects.get(pk=bundle.data["snipt"])
return super(PrivateFavoriteResource, self).obj_create(
bundle, user=bundle.request.user, **kwargs
)

+ 21
- 14
snipts/management/commands/import_snipts.py View File

@@ -8,15 +8,22 @@ import requests


def get_snipts(api_key, from_username, url=None, snipts=[]):
path = url or '/api/private/snipt/?limit=50&api_key={}&username={}&format=json'.format(api_key, from_username)
res = requests.get('https://snippets.siftie.com' + path)
path = (
url
or "/api/private/snipt/?limit=50&api_key={}&username={}&format=json".format(
api_key, from_username
)
)
res = requests.get("https://snippets.siftie.com" + path)
json = res.json()

print(u"Fetched snipts {} through {} of {}".format(
json["meta"]["offset"],
json["meta"]["offset"] + json["meta"]["limit"],
json["meta"]["total_count"]
))
print(
u"Fetched snipts {} through {} of {}".format(
json["meta"]["offset"],
json["meta"]["offset"] + json["meta"]["limit"],
json["meta"]["total_count"],
)
)

snipts.extend(json["objects"])

@@ -30,14 +37,14 @@ class Command(BaseCommand):
help = u"Import snipts from Siftie Snippets."

def add_arguments(self, parser):
parser.add_argument('api_key', nargs='+', type=str)
parser.add_argument('from_username', nargs='+', type=str)
parser.add_argument('to_username', nargs='+', type=str)
parser.add_argument("api_key", nargs="+", type=str)
parser.add_argument("from_username", nargs="+", type=str)
parser.add_argument("to_username", nargs="+", type=str)

def handle(self, *args, **options):
api_key = options['api_key'][0]
from_username = options['from_username'][0]
to_username = options['to_username'][0]
api_key = options["api_key"][0]
from_username = options["from_username"][0]
to_username = options["to_username"][0]
to_user = User.objects.get(username=to_username)

print(u"Fetching snipts...")
@@ -62,7 +69,7 @@ class Command(BaseCommand):
stylized=snipt["stylized"],
title=snipt["title"],
user=to_user,
views=snipt["views"]
views=snipt["views"],
)

s.created = snipt["created"]


+ 69
- 32
snipts/migrations/0001_initial.py View File

@@ -9,53 +9,90 @@ import taggit.managers
class Migration(migrations.Migration):

dependencies = [
('taggit', '0001_initial'),
("taggit", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Favorite',
name="Favorite",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("created", models.DateTimeField(auto_now_add=True)),
("modified", models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='Snipt',
name="Snipt",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(default=b'Untitled', max_length=255, null=True, blank=True)),
('slug', models.SlugField(max_length=255, blank=True)),
('custom_slug', models.SlugField(max_length=255, blank=True)),
('lexer', models.CharField(max_length=50)),
('code', models.TextField()),
('meta', models.TextField(null=True, blank=True)),
('description', models.TextField(null=True, blank=True)),
('stylized', models.TextField(null=True, blank=True)),
('stylized_min', models.TextField(null=True, blank=True)),
('embedded', models.TextField(null=True, blank=True)),
('line_count', models.IntegerField(default=None, null=True, blank=True)),
('key', models.CharField(max_length=100, null=True, blank=True)),
('public', models.BooleanField(default=False)),
('blog_post', models.BooleanField(default=False)),
('views', models.IntegerField(default=0)),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('publish_date', models.DateTimeField(null=True, blank=True)),
('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', help_text='A comma-separated list of tags.', verbose_name='Tags')),
('user', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
(
"title",
models.CharField(
default=b"Untitled", max_length=255, null=True, blank=True
),
),
("slug", models.SlugField(max_length=255, blank=True)),
("custom_slug", models.SlugField(max_length=255, blank=True)),
("lexer", models.CharField(max_length=50)),
("code", models.TextField()),
("meta", models.TextField(null=True, blank=True)),
("description", models.TextField(null=True, blank=True)),
("stylized", models.TextField(null=True, blank=True)),
("stylized_min", models.TextField(null=True, blank=True)),
("embedded", models.TextField(null=True, blank=True)),
(
"line_count",
models.IntegerField(default=None, null=True, blank=True),
),
("key", models.CharField(max_length=100, null=True, blank=True)),
("public", models.BooleanField(default=False)),
("blog_post", models.BooleanField(default=False)),
("views", models.IntegerField(default=0)),
("created", models.DateTimeField(auto_now_add=True)),
("modified", models.DateTimeField(auto_now=True)),
("publish_date", models.DateTimeField(null=True, blank=True)),
(
"tags",
taggit.managers.TaggableManager(
to="taggit.Tag",
through="taggit.TaggedItem",
help_text="A comma-separated list of tags.",
verbose_name="Tags",
),
),
(
"user",
models.ForeignKey(
blank=True, to=settings.AUTH_USER_MODEL, null=True
),
),
],
),
migrations.AddField(
model_name='favorite',
name='snipt',
field=models.ForeignKey(to='snipts.Snipt'),
model_name="favorite",
name="snipt",
field=models.ForeignKey(to="snipts.Snipt"),
),
migrations.AddField(
model_name='favorite',
name='user',
model_name="favorite",
name="user",
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
),
]

+ 18
- 10
snipts/migrations/0002_sniptlogentry.py View File

@@ -9,20 +9,28 @@ class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('snipts', '0001_initial'),
("snipts", "0001_initial"),
]

operations = [
migrations.CreateModel(
name='SniptLogEntry',
name="SniptLogEntry",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('code', models.TextField()),
('diff', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('snipt', models.ForeignKey(to='snipts.Snipt')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("code", models.TextField()),
("diff", models.TextField()),
("created", models.DateTimeField(auto_now_add=True)),
("modified", models.DateTimeField(auto_now=True)),
("snipt", models.ForeignKey(to="snipts.Snipt")),
("user", models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
)
]

+ 10
- 5
snipts/migrations/0003_snipt_last_user_saved.py View File

@@ -9,13 +9,18 @@ class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('snipts', '0002_sniptlogentry'),
("snipts", "0002_sniptlogentry"),
]

operations = [
migrations.AddField(
model_name='snipt',
name='last_user_saved',
field=models.ForeignKey(related_name='last_user_saved', blank=True, to=settings.AUTH_USER_MODEL, null=True),
),
model_name="snipt",
name="last_user_saved",
field=models.ForeignKey(
related_name="last_user_saved",
blank=True,
to=settings.AUTH_USER_MODEL,
null=True,
),
)
]

+ 7
- 9
snipts/migrations/0004_auto_20160512_1058.py View File

@@ -6,19 +6,17 @@ from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
('snipts', '0003_snipt_last_user_saved'),
]
dependencies = [("snipts", "0003_snipt_last_user_saved")]

operations = [
migrations.AddField(
model_name='snipt',
name='secure',
field=models.BooleanField(default=False),
model_name="snipt", name="secure", field=models.BooleanField(default=False)
),
migrations.AlterField(
model_name='snipt',
name='title',
field=models.CharField(max_length=255, blank=True, null=True, default='Untitled'),
model_name="snipt",
name="title",
field=models.CharField(
max_length=255, blank=True, null=True, default="Untitled"
),
),
]

+ 16
- 8
snipts/migrations/0005_sniptsecureview.py View File

@@ -9,18 +9,26 @@ class Migration(migrations.Migration):