So much PEP8.
parent
9e0fded98e
commit
6894f44349
|
@ -2,8 +2,10 @@ from django.contrib import admin
|
||||||
|
|
||||||
from accounts.models import UserProfile
|
from accounts.models import UserProfile
|
||||||
|
|
||||||
|
|
||||||
class UserProfileAdmin(admin.ModelAdmin):
|
class UserProfileAdmin(admin.ModelAdmin):
|
||||||
list_display = ('user', 'is_pro', 'stripe_id', 'gittip_username', 'teams_beta_seen')
|
list_display = ('user', 'is_pro', 'stripe_id', 'gittip_username',
|
||||||
|
'teams_beta_seen')
|
||||||
list_filter = ['teams_beta_seen', 'teams_beta_applied']
|
list_filter = ['teams_beta_seen', 'teams_beta_applied']
|
||||||
search_fields = ('user__username', 'gittip_username',)
|
search_fields = ('user__username', 'gittip_username',)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from datetime import date
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from snipts.models import Snipt
|
from snipts.models import Snipt
|
||||||
|
|
||||||
|
|
||||||
class UserProfile(models.Model):
|
class UserProfile(models.Model):
|
||||||
|
|
||||||
LIST_VIEW_CHOICES = (
|
LIST_VIEW_CHOICES = (
|
||||||
|
@ -42,38 +42,45 @@ class UserProfile(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
# User
|
# User
|
||||||
user = models.OneToOneField(User)
|
user = models.OneToOneField(User)
|
||||||
is_pro = models.BooleanField(default=False)
|
is_pro = models.BooleanField(default=False)
|
||||||
teams_beta_seen = models.BooleanField(default=False)
|
teams_beta_seen = models.BooleanField(default=False)
|
||||||
teams_beta_applied = models.BooleanField(default=False)
|
teams_beta_applied = models.BooleanField(default=False)
|
||||||
pro_date = models.DateTimeField(blank=True, null=True)
|
pro_date = models.DateTimeField(blank=True, null=True)
|
||||||
stripe_id = models.CharField(max_length=100, null=True, blank=True)
|
stripe_id = models.CharField(max_length=100, null=True, blank=True)
|
||||||
has_gravatar = models.BooleanField(default=False)
|
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
|
||||||
blog_title = models.CharField(max_length=250, null=True, blank=True)
|
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,
|
||||||
blog_domain = models.CharField(max_length=250, null=True, blank=True)
|
default='A', choices=THEME_CHOICES)
|
||||||
|
blog_domain = models.CharField(max_length=250, null=True, blank=True)
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
default_editor = models.CharField(max_length=250, null=False, blank=False, default='C', choices=EDITOR_CHOICES)
|
default_editor = models.CharField(max_length=250, null=False, blank=False,
|
||||||
editor_theme = models.CharField(max_length=250, null=False, blank=False, default='default', choices=EDITOR_THEME_CHOICES)
|
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
|
# Services and Analytics
|
||||||
gittip_username = models.CharField(max_length=250, null=True, blank=True)
|
gittip_username = models.CharField(max_length=250, null=True, blank=True)
|
||||||
disqus_shortname = 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,
|
||||||
gauges_site_id = models.CharField(max_length=250, null=True, blank=True)
|
blank=True)
|
||||||
|
gauges_site_id = models.CharField(max_length=250, null=True, blank=True)
|
||||||
|
|
||||||
# Google Ads
|
# Google Ads
|
||||||
google_ad_client = 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_slot = models.CharField(max_length=250, null=True, blank=True)
|
||||||
google_ad_width = 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)
|
google_ad_height = models.CharField(max_length=250, null=True, blank=True)
|
||||||
|
|
||||||
def get_blog_posts(self):
|
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):
|
def get_primary_blog_domain(self):
|
||||||
if not self.blog_domain:
|
if not self.blog_domain:
|
||||||
|
@ -98,10 +105,14 @@ class UserProfile(models.Model):
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def has_public_snipts(self):
|
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
|
||||||
|
|
||||||
def get_account_age(self):
|
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
|
return delta.days
|
||||||
|
|
||||||
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
|
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
|
||||||
|
|
|
@ -2,9 +2,11 @@ from django.conf.urls import *
|
||||||
|
|
||||||
from accounts import views
|
from accounts import views
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = \
|
||||||
url(r'^stats/$', views.stats, name='account-stats'),
|
patterns('',
|
||||||
url(r'^cancel-subscription/$', views.cancel_subscription, name='cancel-subscription'),
|
url(r'^stats/$', views.stats, name='account-stats'),
|
||||||
url(r'^stripe-account-details/$', views.stripe_account_details, name='stripe-account-details'),
|
url(r'^cancel-subscription/$', views.cancel_subscription,
|
||||||
url(r'^', views.account, name='account-detail'),
|
name='cancel-subscription'),
|
||||||
)
|
url(r'^stripe-account-details/$', views.stripe_account_details,
|
||||||
|
name='stripe-account-details'),
|
||||||
|
url(r'^', views.account, name='account-detail'))
|
||||||
|
|
|
@ -3,7 +3,8 @@ from django.contrib.auth.decorators import login_required
|
||||||
from annoying.decorators import ajax_request, render_to
|
from annoying.decorators import ajax_request, render_to
|
||||||
from snipts.models import Snipt
|
from snipts.models import Snipt
|
||||||
|
|
||||||
import os, stripe
|
import os
|
||||||
|
import stripe
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -19,7 +20,8 @@ def cancel_subscription(request):
|
||||||
if request.user.profile.stripe_id is None:
|
if request.user.profile.stripe_id is None:
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY', settings.STRIPE_SECRET_KEY)
|
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY',
|
||||||
|
settings.STRIPE_SECRET_KEY)
|
||||||
customer = stripe.Customer.retrieve(request.user.profile.stripe_id)
|
customer = stripe.Customer.retrieve(request.user.profile.stripe_id)
|
||||||
customer.delete()
|
customer.delete()
|
||||||
|
|
||||||
|
@ -28,7 +30,8 @@ def cancel_subscription(request):
|
||||||
profile.stripe_id = None
|
profile.stripe_id = None
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
return { 'deleted': True }
|
return {'deleted': True}
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ajax_request
|
@ajax_request
|
||||||
|
@ -37,7 +40,8 @@ def stripe_account_details(request):
|
||||||
if request.user.profile.stripe_id is None:
|
if request.user.profile.stripe_id is None:
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY', settings.STRIPE_SECRET_KEY)
|
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY',
|
||||||
|
settings.STRIPE_SECRET_KEY)
|
||||||
customer = stripe.Customer.retrieve(request.user.profile.stripe_id)
|
customer = stripe.Customer.retrieve(request.user.profile.stripe_id)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
|
|
6
admin.py
6
admin.py
|
@ -2,9 +2,11 @@ from django.contrib.auth.admin import UserAdmin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(UserAdmin):
|
class UserAdmin(UserAdmin):
|
||||||
list_display = ['username', 'email', 'first_name', 'last_name', 'last_login',
|
list_display = ['username', 'email', 'first_name', 'last_name',
|
||||||
'date_joined', 'is_active', 'is_staff', 'api_key']
|
'last_login', 'date_joined', 'is_active', 'is_staff',
|
||||||
|
'api_key']
|
||||||
list_filter = ['is_staff', 'is_superuser', 'is_active']
|
list_filter = ['is_staff', 'is_superuser', 'is_active']
|
||||||
ordering = ['-date_joined']
|
ordering = ['-date_joined']
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,26 @@ class BlogMiddleware:
|
||||||
host = request.META.get('HTTP_HOST', '')
|
host = request.META.get('HTTP_HOST', '')
|
||||||
host_s = host.replace('www.', '').split('.')
|
host_s = host.replace('www.', '').split('.')
|
||||||
|
|
||||||
if host != 'snipt.net' and host != 'snipt.localhost' and host != 'local.snipt.net':
|
if host != 'snipt.net' and \
|
||||||
|
host != 'snipt.localhost' and \
|
||||||
|
host != 'local.snipt.net':
|
||||||
if len(host_s) > 2:
|
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:
|
if '-' in blog_user:
|
||||||
request.blog_user = get_object_or_None(User, username__iexact=blog_user)
|
request.blog_user = \
|
||||||
|
get_object_or_None(User,
|
||||||
|
username__iexact=blog_user)
|
||||||
|
|
||||||
if request.blog_user is None:
|
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:
|
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:
|
if request.blog_user is None:
|
||||||
pro_users = User.objects.filter(userprofile__is_pro=True)
|
pro_users = User.objects.filter(userprofile__is_pro=True)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from django.conf.urls import *
|
from django.conf.urls import *
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('', url(r'^$', views.blog, name='blog'))
|
||||||
url(r'^$', views.blog, name='blog'),
|
|
||||||
)
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ THEME_CHOICES = {
|
||||||
'A': 'blogs/themes/pro-adams/',
|
'A': 'blogs/themes/pro-adams/',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def blog_list(request, username_or_custom_slug=None):
|
def blog_list(request, username_or_custom_slug=None):
|
||||||
|
|
||||||
if username_or_custom_slug:
|
if username_or_custom_slug:
|
||||||
|
@ -19,17 +20,25 @@ def blog_list(request, username_or_custom_slug=None):
|
||||||
snipts = Snipt.objects.filter(user=request.blog_user,
|
snipts = Snipt.objects.filter(user=request.blog_user,
|
||||||
blog_post=True,
|
blog_post=True,
|
||||||
public=True,
|
public=True,
|
||||||
publish_date__lte=datetime.datetime.now()
|
publish_date__lte=datetime.datetime.now()) \
|
||||||
).order_by('-publish_date').exclude(title__iexact='Homepage').exclude(title__iexact='Work')
|
.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 = 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(title__in=[''])
|
||||||
normal_snipts = normal_snipts.exclude(tags__name__in=['tmp'])
|
normal_snipts = normal_snipts.exclude(tags__name__in=['tmp'])
|
||||||
normal_snipts = normal_snipts[:3]
|
normal_snipts = normal_snipts[:3]
|
||||||
|
|
||||||
sidebar = get_object_or_None(Snipt, user=request.blog_user, title='Sidebar', blog_post=True)
|
sidebar = get_object_or_None(Snipt, user=request.blog_user,
|
||||||
header = get_object_or_None(Snipt, user=request.blog_user, title='Header', blog_post=True)
|
title='Sidebar', blog_post=True)
|
||||||
custom_css = get_object_or_None(Snipt, user=request.blog_user, title='CSS', lexer='css', 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 = {
|
context = {
|
||||||
'blog_user': request.blog_user,
|
'blog_user': request.blog_user,
|
||||||
|
@ -55,26 +64,33 @@ def blog_list(request, username_or_custom_slug=None):
|
||||||
context,
|
context,
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
def blog_post(request, username_or_custom_slug):
|
def blog_post(request, username_or_custom_slug):
|
||||||
|
|
||||||
snipt = get_object_or_404(Snipt, user=request.blog_user,
|
snipt = get_object_or_404(Snipt, user=request.blog_user,
|
||||||
blog_post=True,
|
blog_post=True,
|
||||||
public=True,
|
public=True,
|
||||||
publish_date__lte=datetime.datetime.now(),
|
publish_date__lte=datetime.datetime.now(),
|
||||||
slug=username_or_custom_slug,
|
slug=username_or_custom_slug)
|
||||||
)
|
|
||||||
|
|
||||||
snipts = Snipt.objects.filter(user=request.blog_user,
|
snipts = Snipt.objects.filter(user=request.blog_user,
|
||||||
blog_post=True,
|
blog_post=True,
|
||||||
public=True,
|
public=True,
|
||||||
publish_date__lte=datetime.datetime.now()
|
publish_date__lte=datetime.datetime.now()) \
|
||||||
).order_by('-publish_date').exclude(title__iexact='Homepage').exclude(title__iexact='Work')
|
.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)
|
sidebar = get_object_or_None(Snipt, user=request.blog_user,
|
||||||
header = get_object_or_None(Snipt, user=request.blog_user, title='Header', blog_post=True)
|
title='Sidebar', blog_post=True)
|
||||||
custom_css = get_object_or_None(Snipt, user=request.blog_user, title='CSS', lexer='css', 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 = 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(title__in=[''])
|
||||||
normal_snipts = normal_snipts.exclude(tags__name__in=['tmp'])
|
normal_snipts = normal_snipts.exclude(tags__name__in=['tmp'])
|
||||||
normal_snipts = normal_snipts[:3]
|
normal_snipts = normal_snipts[:3]
|
||||||
|
@ -100,16 +116,13 @@ def blog_post(request, username_or_custom_slug):
|
||||||
|
|
||||||
template = '{}/post.html'.format(template)
|
template = '{}/post.html'.format(template)
|
||||||
|
|
||||||
return render_to_response(
|
return render_to_response(template,
|
||||||
template,
|
context,
|
||||||
context,
|
context_instance=RequestContext(request))
|
||||||
context_instance=RequestContext(request)
|
|
||||||
)
|
|
||||||
|
|
||||||
def rss(request, context):
|
def rss(request, context):
|
||||||
return render_to_response(
|
return render_to_response('blogs/themes/default/rss.xml',
|
||||||
'blogs/themes/default/rss.xml',
|
context,
|
||||||
context,
|
context_instance=RequestContext(request),
|
||||||
context_instance=RequestContext(request),
|
content_type="application/rss+xml")
|
||||||
content_type="application/rss+xml"
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
from django.contrib import admin
|
|
||||||
from jobs.models import Job
|
|
||||||
|
|
||||||
|
|
||||||
class JobAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('title', 'created', 'company', 'url',)
|
|
||||||
ordering = ('-created',)
|
|
||||||
|
|
||||||
admin.site.register(Job, JobAdmin)
|
|
|
@ -1,48 +0,0 @@
|
||||||
from django.conf import settings
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
from jobs.models import Job
|
|
||||||
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = 'Import jobs'
|
|
||||||
listings = []
|
|
||||||
|
|
||||||
def get_for_page(self, page):
|
|
||||||
r = requests.get('{}&page={}'.format(settings.JOBS_BASE_URL, page))
|
|
||||||
obj = r.json()
|
|
||||||
self.listings.extend(obj['listings']['listing'])
|
|
||||||
|
|
||||||
if page < obj['listings']['pages']:
|
|
||||||
return self.get_for_page(page + 1)
|
|
||||||
|
|
||||||
return self.listings
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
listings = self.get_for_page(1)
|
|
||||||
|
|
||||||
jobs = Job.objects.all()
|
|
||||||
for job in jobs:
|
|
||||||
job.delete()
|
|
||||||
|
|
||||||
for listing in listings:
|
|
||||||
|
|
||||||
try:
|
|
||||||
location = listing['company']['location']['city']
|
|
||||||
except:
|
|
||||||
location = ''
|
|
||||||
|
|
||||||
try:
|
|
||||||
company = str(listing['company']['name'])
|
|
||||||
except:
|
|
||||||
company = ''
|
|
||||||
|
|
||||||
newjob = Job(title=listing['title'],
|
|
||||||
company=company,
|
|
||||||
location=location,
|
|
||||||
url=listing['url'],
|
|
||||||
data=json.dumps(listing),
|
|
||||||
created=listing['post_date'])
|
|
||||||
newjob.save()
|
|
|
@ -1,25 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Job',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
|
||||||
('title', models.CharField(max_length=255)),
|
|
||||||
('company', models.CharField(max_length=255)),
|
|
||||||
('location', models.CharField(max_length=255)),
|
|
||||||
('url', models.CharField(max_length=255)),
|
|
||||||
('data', models.TextField(null=True, blank=True)),
|
|
||||||
('created', models.DateTimeField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,16 +0,0 @@
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class Job(models.Model):
|
|
||||||
"""An individual Job."""
|
|
||||||
|
|
||||||
title = models.CharField(max_length=255)
|
|
||||||
company = models.CharField(max_length=255)
|
|
||||||
location = models.CharField(max_length=255)
|
|
||||||
url = models.CharField(max_length=255)
|
|
||||||
data = models.TextField(blank=True, null=True)
|
|
||||||
|
|
||||||
created = models.DateTimeField()
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return self.title
|
|
|
@ -1,70 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% load humanize %}
|
|
||||||
{% load pagination_tags %}
|
|
||||||
|
|
||||||
{% block page-title %}Snipt Jobs{% endblock %}
|
|
||||||
|
|
||||||
{% block body-class %}{{ block.super }} static jobs search{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
window.jobs = [
|
|
||||||
{% for job in jobs %}
|
|
||||||
{{ job.data|safe }}{% if not forloop.last %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
];
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumb %}
|
|
||||||
<li><a href="/jobs/">Snipt Jobs</a></li>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div ng-controller="JobSearchController" ng-cloak class="ng-cloak">
|
|
||||||
<div class="static-box {% if page.object_list|length > 0 %}has-snipts{% endif %}">
|
|
||||||
<form method="get" class="form-search" action=".">
|
|
||||||
<input ng-model="query" type="text" class="search-query" name="q" placeholder="Filter jobs" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="loading-jobs" ng-show="!jobs">
|
|
||||||
Loading jobs…
|
|
||||||
</div>
|
|
||||||
<div class="pagination ng-cloak" ng-cloak ng-show="jobs">
|
|
||||||
<button class="btn prev" style="margin: 0 10px;" href ng-disabled="currentPage == 0" ng-click="currentPage=currentPage - 1">Previous</button>
|
|
||||||
<span class="page">{[{ currentPage + 1 }]} / {[{ numberOfPages() }]}</span>
|
|
||||||
<button class="btn next" style="margin: 0 10px;" ng-disabled="currentPage >= filteredJobs.length / pageSize - 1" ng-click="currentPage=currentPage + 1">Next</button>
|
|
||||||
</div>
|
|
||||||
<section class="jobs">
|
|
||||||
<ul>
|
|
||||||
<li ng-repeat="job in filteredJobs|startFrom:currentPage * pageSize|limitTo:pageSize">
|
|
||||||
<a href="{[{ job.url }]}?aff=dbe7e" class="group job-link">
|
|
||||||
<img ng-show="job.company.logo" ng-src="{[{ job.company.logo }]}" />
|
|
||||||
<span class="left">
|
|
||||||
<span class="job">{[{ job.title }]}</span>
|
|
||||||
<span class="company">{[{ job.company.name }]}</span>
|
|
||||||
</span>
|
|
||||||
<span class="right">
|
|
||||||
<span class="location">{[{ job.company.location.city }]}</span>
|
|
||||||
<span class="date">{[{ job.created }]}</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<div class="pagination ng-cloak" ng-cloak ng-show="jobs">
|
|
||||||
<button class="btn prev" style="margin: 0 10px;" href ng-disabled="currentPage == 0" ng-click="currentPage=currentPage - 1">Previous</button>
|
|
||||||
<span class="page">{[{ currentPage + 1 }]} / {[{ numberOfPages() }]}</span>
|
|
||||||
<button class="btn next" style="margin: 0 10px;" ng-disabled="currentPage >= filteredJobs.length / pageSize - 1" ng-click="currentPage=currentPage + 1">Next</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block ad %}{% endblock %}
|
|
||||||
{% block aside-top %}
|
|
||||||
<div class="post-job">
|
|
||||||
<a id="post-job" href="http://www.authenticjobs.com/post/?aff=dbe7e" class="btn btn-large btn-success">Post a job</a>
|
|
||||||
<p>
|
|
||||||
We use <a class="job-link" href="http://www.authenticjobs.com?aff=dbe7e">Authentic Jobs</a> for our job board provider. Once you post your ad, it will appear on Snipt within 30 minutes.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,16 +0,0 @@
|
||||||
"""
|
|
||||||
This file demonstrates writing tests using the unittest module. These will pass
|
|
||||||
when you run "manage.py test".
|
|
||||||
|
|
||||||
Replace this with more appropriate tests for your application.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
|
||||||
def test_basic_addition(self):
|
|
||||||
"""
|
|
||||||
Tests that 1 + 1 always equals 2.
|
|
||||||
"""
|
|
||||||
self.assertEqual(1 + 1, 2)
|
|
|
@ -1,22 +0,0 @@
|
||||||
from annoying.decorators import ajax_request, render_to
|
|
||||||
from jobs.models import Job
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
@render_to('jobs/jobs.html')
|
|
||||||
def jobs(request):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
@ajax_request
|
|
||||||
def jobs_json(request):
|
|
||||||
|
|
||||||
jobs_json = []
|
|
||||||
|
|
||||||
jobs = Job.objects.all().order_by('-created')
|
|
||||||
|
|
||||||
for job in jobs:
|
|
||||||
jobs_json.append(json.loads(job.data))
|
|
||||||
|
|
||||||
return jobs_json
|
|
24
settings.py
24
settings.py
|
@ -1,13 +1,15 @@
|
||||||
import dj_database_url, os
|
import dj_database_url
|
||||||
|
import os
|
||||||
|
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
|
||||||
if 'DATABASE_URL' in os.environ:
|
if 'DATABASE_URL' in os.environ:
|
||||||
|
|
||||||
DATABASES = { 'default': dj_database_url.config() }
|
DATABASES = {'default': dj_database_url.config()}
|
||||||
|
|
||||||
es = urlparse(os.environ.get('SEARCHBOX_SSL_URL') or 'http://127.0.0.1:9200/')
|
es = urlparse(os.environ.get('SEARCHBOX_SSL_URL') or
|
||||||
|
'http://127.0.0.1:9200/')
|
||||||
port = es.port or 80
|
port = es.port or 80
|
||||||
|
|
||||||
HAYSTACK_CONNECTIONS = {
|
HAYSTACK_CONNECTIONS = {
|
||||||
|
@ -19,9 +21,11 @@ if 'DATABASE_URL' in os.environ:
|
||||||
}
|
}
|
||||||
|
|
||||||
if es.username:
|
if es.username:
|
||||||
HAYSTACK_CONNECTIONS['default']['KWARGS'] = {"http_auth": es.username + ':' + es.password}
|
HAYSTACK_CONNECTIONS['default']['KWARGS'] = {
|
||||||
|
"http_auth": es.username + ':' + es.password
|
||||||
|
}
|
||||||
|
|
||||||
ABSOLUTE_URL_OVERRIDES = { 'auth.user': lambda u: "/%s/" % u.username, }
|
ABSOLUTE_URL_OVERRIDES = {'auth.user': lambda u: "/%s/" % u.username}
|
||||||
ACCOUNT_ACTIVATION_DAYS = 0
|
ACCOUNT_ACTIVATION_DAYS = 0
|
||||||
ADMINS = (('Nick Sergeant', 'nick@snipt.net'),)
|
ADMINS = (('Nick Sergeant', 'nick@snipt.net'),)
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
@ -46,7 +50,7 @@ MEDIA_URL = '/media/uploads/'
|
||||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
||||||
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__))
|
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||||
RAVEN_CONFIG = { 'dsn': os.environ.get('RAVEN_CONFIG_DSN', '') }
|
RAVEN_CONFIG = {'dsn': os.environ.get('RAVEN_CONFIG_DSN', '')}
|
||||||
REGISTRATION_EMAIL_HTML = False
|
REGISTRATION_EMAIL_HTML = False
|
||||||
ROOT_URLCONF = 'urls'
|
ROOT_URLCONF = 'urls'
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY', 'changeme')
|
SECRET_KEY = os.environ.get('SECRET_KEY', 'changeme')
|
||||||
|
@ -57,11 +61,14 @@ 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
|
SITE_ID = 1
|
||||||
STATICFILES_DIRS = (os.path.join(BASE_PATH, 'media'),)
|
STATICFILES_DIRS = (os.path.join(BASE_PATH, 'media'),)
|
||||||
STATICFILES_FINDERS = ('django.contrib.staticfiles.finders.FileSystemFinder','django.contrib.staticfiles.finders.AppDirectoriesFinder',)
|
STATICFILES_FINDERS = ('django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder')
|
||||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
|
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
|
||||||
STATIC_ROOT = os.path.join(BASE_PATH, 'static')
|
STATIC_ROOT = os.path.join(BASE_PATH, 'static')
|
||||||
STATIC_URL = '/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 api@snipt.net and we'll help you out."
|
TASTYPIE_CANNED_ERROR = """There was an error with your request. The site
|
||||||
|
developers have a record of this error, please email api@snipt.net and
|
||||||
|
we'll help you out."""
|
||||||
TEMPLATE_DIRS = (os.path.join(PROJECT_PATH, 'templates'),)
|
TEMPLATE_DIRS = (os.path.join(PROJECT_PATH, 'templates'),)
|
||||||
TEMPLATE_DEBUG = DEBUG
|
TEMPLATE_DEBUG = DEBUG
|
||||||
TIME_ZONE = 'America/New_York'
|
TIME_ZONE = 'America/New_York'
|
||||||
|
@ -93,7 +100,6 @@ INSTALLED_APPS = (
|
||||||
'typogrify',
|
'typogrify',
|
||||||
'accounts',
|
'accounts',
|
||||||
'blogs',
|
'blogs',
|
||||||
'jobs',
|
|
||||||
'snipts',
|
'snipts',
|
||||||
'utils',
|
'utils',
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,7 +2,7 @@ CSRF_COOKIE_SECURE = False
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
INTERCOM_SECRET_KEY = ''
|
INTERCOM_SECRET_KEY = ''
|
||||||
POSTMARK_API_KEY = ''
|
POSTMARK_API_KEY = ''
|
||||||
RAVEN_CONFIG = { 'dsn': '' }
|
RAVEN_CONFIG = {'dsn': ''}
|
||||||
SECRET_KEY = 'changeme'
|
SECRET_KEY = 'changeme'
|
||||||
SESSION_COOKIE_SECURE = False
|
SESSION_COOKIE_SECURE = False
|
||||||
SSLIFY_DISABLE = False
|
SSLIFY_DISABLE = False
|
||||||
|
|
|
@ -5,7 +5,9 @@ from snipts.models import Favorite, Snipt
|
||||||
|
|
||||||
class SniptAdmin(admin.ModelAdmin):
|
class SniptAdmin(admin.ModelAdmin):
|
||||||
readonly_fields = ('user',)
|
readonly_fields = ('user',)
|
||||||
list_display = ('title', 'slug', 'views', 'favs', 'user', 'lexer', 'public', 'blog_post', 'created', 'modified', 'publish_date',)
|
list_display = ('title', 'slug', 'views', 'favs', 'user', 'lexer',
|
||||||
|
'public', 'blog_post', 'created', 'modified',
|
||||||
|
'publish_date')
|
||||||
list_filter = ('blog_post',)
|
list_filter = ('blog_post',)
|
||||||
search_fields = ('title', 'slug', 'user__username', 'lexer', 'id', 'key',)
|
search_fields = ('title', 'slug', 'user__username', 'lexer', 'id', 'key',)
|
||||||
ordering = ('-created',)
|
ordering = ('-created',)
|
||||||
|
@ -13,6 +15,7 @@ class SniptAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
admin.site.register(Snipt, SniptAdmin)
|
admin.site.register(Snipt, SniptAdmin)
|
||||||
|
|
||||||
|
|
||||||
class FavoriteAdmin(admin.ModelAdmin):
|
class FavoriteAdmin(admin.ModelAdmin):
|
||||||
readonly_fields = ('snipt', 'user',)
|
readonly_fields = ('snipt', 'user',)
|
||||||
list_display = ('snipt', 'user', 'created',)
|
list_display = ('snipt', 'user', 'created',)
|
||||||
|
|
118
snipts/api.py
118
snipts/api.py
|
@ -12,12 +12,14 @@ from haystack.query import SearchQuerySet
|
||||||
from accounts.models import UserProfile
|
from accounts.models import UserProfile
|
||||||
from tastypie.cache import SimpleCache
|
from tastypie.cache import SimpleCache
|
||||||
from tastypie.fields import ListField
|
from tastypie.fields import ListField
|
||||||
from django.http import HttpResponse
|
|
||||||
from taggit.models import Tag
|
from taggit.models import Tag
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from tastypie import fields
|
from tastypie import fields
|
||||||
|
|
||||||
import datetime, hashlib, time, re
|
import datetime
|
||||||
|
import hashlib
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
import parsedatetime as pdt
|
import parsedatetime as pdt
|
||||||
|
|
||||||
|
@ -49,6 +51,7 @@ class PrivateFavoriteAuthorization(Authorization):
|
||||||
def delete_detail(self, object_list, bundle):
|
def delete_detail(self, object_list, bundle):
|
||||||
return bundle.obj.user == bundle.request.user
|
return bundle.obj.user == bundle.request.user
|
||||||
|
|
||||||
|
|
||||||
class PrivateSniptAuthorization(Authorization):
|
class PrivateSniptAuthorization(Authorization):
|
||||||
def read_list(self, object_list, bundle):
|
def read_list(self, object_list, bundle):
|
||||||
return object_list.filter(user=bundle.request.user)
|
return object_list.filter(user=bundle.request.user)
|
||||||
|
@ -74,6 +77,7 @@ class PrivateSniptAuthorization(Authorization):
|
||||||
def delete_detail(self, object_list, bundle):
|
def delete_detail(self, object_list, bundle):
|
||||||
return bundle.obj.user == bundle.request.user
|
return bundle.obj.user == bundle.request.user
|
||||||
|
|
||||||
|
|
||||||
class PrivateUserProfileAuthorization(Authorization):
|
class PrivateUserProfileAuthorization(Authorization):
|
||||||
def read_list(self, object_list, bundle):
|
def read_list(self, object_list, bundle):
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
@ -99,6 +103,7 @@ class PrivateUserProfileAuthorization(Authorization):
|
||||||
def delete_detail(self, object_list, bundle):
|
def delete_detail(self, object_list, bundle):
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
|
||||||
|
|
||||||
class PrivateUserAuthorization(Authorization):
|
class PrivateUserAuthorization(Authorization):
|
||||||
def read_list(self, object_list, bundle):
|
def read_list(self, object_list, bundle):
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
@ -130,22 +135,27 @@ class FavoriteValidation(Validation):
|
||||||
errors = {}
|
errors = {}
|
||||||
snipt = bundle.data['snipt']
|
snipt = bundle.data['snipt']
|
||||||
|
|
||||||
if Favorite.objects.filter(user=bundle.request.user, snipt=snipt).count():
|
if Favorite.objects.filter(user=bundle.request.user,
|
||||||
|
snipt=snipt).count():
|
||||||
errors['duplicate'] = 'User has already favorited this snipt.'
|
errors['duplicate'] = 'User has already favorited this snipt.'
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
class SniptValidation(Validation):
|
class SniptValidation(Validation):
|
||||||
def is_valid(self, bundle, request=None):
|
def is_valid(self, bundle, request=None):
|
||||||
errors = {}
|
errors = {}
|
||||||
|
|
||||||
if 'pk' not in bundle.data and \
|
if 'pk' not in bundle.data and \
|
||||||
request.user.profile.get_account_age() > 7 and \
|
request.user.profile.get_account_age() > 7 and \
|
||||||
request.user.profile.is_pro == False:
|
request.user.profile.is_pro is False:
|
||||||
errors['expired'] = "Your trial has expired. You'll need to go Pro (https://snipt.net/pro/) in order to create new snipts."
|
errors['expired'] = """Your trial has expired. You'll need
|
||||||
|
to go Pro (https://snipt.net/pro/)
|
||||||
|
in order to create new snipts."""
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
class UserProfileValidation(Validation):
|
class UserProfileValidation(Validation):
|
||||||
def is_valid(self, bundle, request=None):
|
def is_valid(self, bundle, request=None):
|
||||||
errors = {}
|
errors = {}
|
||||||
|
@ -153,7 +163,9 @@ class UserProfileValidation(Validation):
|
||||||
for field in bundle.data:
|
for field in bundle.data:
|
||||||
if bundle.data[field]:
|
if bundle.data[field]:
|
||||||
if not re.match('^[ A-Za-z0-9\/\@\._-]*$', 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.'
|
errors[field] = """Only spaces, letters, numbers,
|
||||||
|
underscores, dashes, periods, forward
|
||||||
|
slashes, and "at sign" are valid."""
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
@ -162,26 +174,31 @@ class PublicUserResource(ModelResource):
|
||||||
class Meta:
|
class Meta:
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
resource_name = 'user'
|
resource_name = 'user'
|
||||||
fields = ['id', 'username',]
|
fields = ['id', 'username']
|
||||||
include_absolute_url = True
|
include_absolute_url = True
|
||||||
allowed_methods = ['get']
|
allowed_methods = ['get']
|
||||||
filtering = { 'username': 'exact', }
|
filtering = {'username': 'exact'}
|
||||||
max_limit = 200
|
max_limit = 200
|
||||||
cache = SimpleCache()
|
cache = SimpleCache()
|
||||||
|
|
||||||
def dehydrate(self, bundle):
|
def dehydrate(self, bundle):
|
||||||
bundle.data['snipts'] = '/api/public/snipt/?user=%d' % bundle.obj.id
|
bundle.data['snipts'] = '/api/public/snipt/?user=%d' % bundle.obj.id
|
||||||
bundle.data['email_md5'] = hashlib.md5(bundle.obj.email.lower()).hexdigest()
|
bundle.data['email_md5'] = hashlib \
|
||||||
bundle.data['snipts_count'] = Snipt.objects.filter(user=bundle.obj.id, public=True).count()
|
.md5(bundle.obj.email.lower()) \
|
||||||
|
.hexdigest()
|
||||||
|
bundle.data['snipts_count'] = Snipt.objects.filter(user=bundle.obj.id,
|
||||||
|
public=True).count()
|
||||||
return bundle
|
return bundle
|
||||||
|
|
||||||
|
|
||||||
class PublicTagResource(ModelResource):
|
class PublicTagResource(ModelResource):
|
||||||
class Meta:
|
class Meta:
|
||||||
queryset = Tag.objects.filter()
|
queryset = Tag.objects.filter()
|
||||||
queryset = queryset.annotate(count=models.Count('taggit_taggeditem_items__id'))
|
queryset = queryset.annotate(
|
||||||
|
count=models.Count('taggit_taggeditem_items__id'))
|
||||||
queryset = queryset.order_by('-count', 'name')
|
queryset = queryset.order_by('-count', 'name')
|
||||||
resource_name = 'tag'
|
resource_name = 'tag'
|
||||||
fields = ['id', 'name',]
|
fields = ['id', 'name']
|
||||||
allowed_methods = ['get']
|
allowed_methods = ['get']
|
||||||
max_limit = 200
|
max_limit = 200
|
||||||
cache = SimpleCache()
|
cache = SimpleCache()
|
||||||
|
@ -202,19 +219,22 @@ class PublicTagResource(ModelResource):
|
||||||
bundle.data['snipts'] = '/api/public/snipt/?tag=%d' % bundle.obj.id
|
bundle.data['snipts'] = '/api/public/snipt/?tag=%d' % bundle.obj.id
|
||||||
return bundle
|
return bundle
|
||||||
|
|
||||||
|
|
||||||
class PublicSniptResource(ModelResource):
|
class PublicSniptResource(ModelResource):
|
||||||
user = fields.ForeignKey(PublicUserResource, 'user', full=True)
|
user = fields.ForeignKey(PublicUserResource, 'user', full=True)
|
||||||
tags = fields.ToManyField(PublicTagResource, 'tags', related_name='tag', full=True)
|
tags = fields.ToManyField(PublicTagResource, 'tags', related_name='tag',
|
||||||
|
full=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
queryset = Snipt.objects.filter(public=True).order_by('-created')
|
queryset = Snipt.objects.filter(public=True).order_by('-created')
|
||||||
resource_name = 'snipt'
|
resource_name = 'snipt'
|
||||||
fields = ['id', 'title', 'slug', 'lexer', 'code', 'description', 'line_count',
|
fields = ['id', 'title', 'slug', 'lexer', 'code', 'description',
|
||||||
'stylized', 'created', 'modified', 'publish_date', 'blog_post', 'meta',]
|
'line_count', 'stylized', 'created', 'modified',
|
||||||
|
'publish_date', 'blog_post', 'meta']
|
||||||
include_absolute_url = True
|
include_absolute_url = True
|
||||||
allowed_methods = ['get']
|
allowed_methods = ['get']
|
||||||
filtering = { 'user': 'exact', 'blog_post': 'exact' }
|
filtering = {'user': 'exact', 'blog_post': 'exact'}
|
||||||
ordering = ['created', 'modified',]
|
ordering = ['created', 'modified']
|
||||||
max_limit = 200
|
max_limit = 200
|
||||||
cache = SimpleCache()
|
cache = SimpleCache()
|
||||||
|
|
||||||
|
@ -222,7 +242,8 @@ class PublicSniptResource(ModelResource):
|
||||||
bundle.data['embed_url'] = bundle.obj.get_embed_url()
|
bundle.data['embed_url'] = bundle.obj.get_embed_url()
|
||||||
bundle.data['raw_url'] = bundle.obj.get_raw_url()
|
bundle.data['raw_url'] = bundle.obj.get_raw_url()
|
||||||
bundle.data['full_absolute_url'] = bundle.obj.get_full_absolute_url()
|
bundle.data['full_absolute_url'] = bundle.obj.get_full_absolute_url()
|
||||||
bundle.data['description_rendered'] = linebreaksbr(urlize(bundle.obj.description))
|
bundle.data['description_rendered'] = \
|
||||||
|
linebreaksbr(urlize(bundle.obj.description))
|
||||||
|
|
||||||
if 'omit_code' in bundle.request.GET:
|
if 'omit_code' in bundle.request.GET:
|
||||||
del bundle.data['code']
|
del bundle.data['code']
|
||||||
|
@ -272,8 +293,10 @@ class PrivateUserProfileResource(ModelResource):
|
||||||
bundle.data['is_pro'] = bundle.obj.user.profile.is_pro
|
bundle.data['is_pro'] = bundle.obj.user.profile.is_pro
|
||||||
return bundle
|
return bundle
|
||||||
|
|
||||||
|
|
||||||
class PrivateUserResource(ModelResource):
|
class PrivateUserResource(ModelResource):
|
||||||
profile = fields.ForeignKey(PrivateUserProfileResource, 'profile', full=False)
|
profile = fields.ForeignKey(PrivateUserProfileResource, 'profile',
|
||||||
|
full=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
|
@ -289,18 +312,25 @@ class PrivateUserResource(ModelResource):
|
||||||
cache = SimpleCache()
|
cache = SimpleCache()
|
||||||
|
|
||||||
def dehydrate(self, bundle):
|
def dehydrate(self, bundle):
|
||||||
bundle.data['email_md5'] = hashlib.md5(bundle.obj.email.lower()).hexdigest()
|
bundle.data['email_md5'] = hashlib \
|
||||||
|
.md5(bundle.obj.email.lower()) \
|
||||||
|
.hexdigest()
|
||||||
bundle.data['is_pro'] = bundle.obj.profile.is_pro
|
bundle.data['is_pro'] = bundle.obj.profile.is_pro
|
||||||
bundle.data['stats'] = {
|
bundle.data['stats'] = {
|
||||||
'public_snipts': Snipt.objects.filter(user=bundle.obj.id, public=True).count(),
|
'public_snipts': Snipt.objects.filter(user=bundle.obj.id,
|
||||||
'private_snipts': Snipt.objects.filter(user=bundle.obj.id, public=False).count(),
|
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_snipts': Snipt.objects.filter(user=bundle.obj.id).count(),
|
||||||
'total_views': Snipt.objects.filter(user=bundle.obj.id).aggregate(models.Sum('views'))['views__sum']
|
'total_views': Snipt.objects.filter(user=bundle.obj.id).aggregate(
|
||||||
|
models.Sum('views'))['views__sum']
|
||||||
}
|
}
|
||||||
bundle.data['lexers'] = [snipt['lexer'] for snipt in \
|
bundle.data['lexers'] = [
|
||||||
Snipt.objects.filter(user=bundle.obj).values('lexer').distinct()]
|
snipt['lexer'] for snipt in Snipt.objects.filter(user=bundle.obj)
|
||||||
|
.values('lexer').distinct()]
|
||||||
return bundle
|
return bundle
|
||||||
|
|
||||||
|
|
||||||
class PrivateSniptResource(ModelResource):
|
class PrivateSniptResource(ModelResource):
|
||||||
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
|
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
|
||||||
tags_list = ListField()
|
tags_list = ListField()
|
||||||
|
@ -308,15 +338,16 @@ class PrivateSniptResource(ModelResource):
|
||||||
class Meta:
|
class Meta:
|
||||||
queryset = Snipt.objects.all().order_by('-created')
|
queryset = Snipt.objects.all().order_by('-created')
|
||||||
resource_name = 'snipt'
|
resource_name = 'snipt'
|
||||||
fields = ['id', 'title', 'slug', 'lexer', 'code', 'description', 'line_count', 'stylized',
|
fields = ['id', 'title', 'slug', 'lexer', 'code', 'description',
|
||||||
'key', 'public', 'blog_post', 'created', 'modified', 'publish_date', 'meta',]
|
'line_count', 'stylized', 'key', 'public', 'blog_post',
|
||||||
|
'created', 'modified', 'publish_date', 'meta']
|
||||||
include_absolute_url = True
|
include_absolute_url = True
|
||||||
detail_allowed_methods = ['get', 'patch', 'put', 'delete']
|
detail_allowed_methods = ['get', 'patch', 'put', 'delete']
|
||||||
list_allowed_methods = ['get', 'post']
|
list_allowed_methods = ['get', 'post']
|
||||||
authentication = ApiKeyAuthentication()
|
authentication = ApiKeyAuthentication()
|
||||||
authorization = PrivateSniptAuthorization()
|
authorization = PrivateSniptAuthorization()
|
||||||
validation = SniptValidation()
|
validation = SniptValidation()
|
||||||
ordering = ['created', 'modified',]
|
ordering = ['created', 'modified']
|
||||||
always_return_data = True
|
always_return_data = True
|
||||||
max_limit = 200
|
max_limit = 200
|
||||||
cache = SimpleCache()
|
cache = SimpleCache()
|
||||||
|
@ -326,12 +357,14 @@ class PrivateSniptResource(ModelResource):
|
||||||
bundle.data['raw_url'] = bundle.obj.get_raw_url()
|
bundle.data['raw_url'] = bundle.obj.get_raw_url()
|
||||||
bundle.data['tags_list'] = edit_string_for_tags(bundle.obj.tags.all())
|
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['full_absolute_url'] = bundle.obj.get_full_absolute_url()
|
||||||
bundle.data['description_rendered'] = linebreaksbr(urlize(bundle.obj.description))
|
bundle.data['description_rendered'] = \
|
||||||
|
linebreaksbr(urlize(bundle.obj.description))
|
||||||
bundle.data['views'] = bundle.obj.views
|
bundle.data['views'] = bundle.obj.views
|
||||||
bundle.data['favs'] = bundle.obj.favs()
|
bundle.data['favs'] = bundle.obj.favs()
|
||||||
|
|
||||||
if bundle.data['publish_date']:
|
if bundle.data['publish_date']:
|
||||||
bundle.data['publish_date'] = date(bundle.data['publish_date'], 'M d, Y \\a\\t h:i A')
|
bundle.data['publish_date'] = \
|
||||||
|
date(bundle.data['publish_date'], 'M d, Y \\a\\t h:i A')
|
||||||
|
|
||||||
return bundle
|
return bundle
|
||||||
|
|
||||||
|
@ -342,8 +375,9 @@ class PrivateSniptResource(ModelResource):
|
||||||
if 'blog_post' in bundle.data:
|
if 'blog_post' in bundle.data:
|
||||||
bundle = self._clean_publish_date(bundle)
|
bundle = self._clean_publish_date(bundle)
|
||||||
|
|
||||||
return super(PrivateSniptResource, self).obj_create(bundle,
|
return super(PrivateSniptResource, self) \
|
||||||
user=bundle.request.user, **kwargs)
|
.obj_create(bundle,
|
||||||
|
user=bundle.request.user, **kwargs)
|
||||||
|
|
||||||
def obj_update(self, bundle, **kwargs):
|
def obj_update(self, bundle, **kwargs):
|
||||||
bundle.data['user'] = bundle.request.user
|
bundle.data['user'] = bundle.request.user
|
||||||
|
@ -359,8 +393,9 @@ class PrivateSniptResource(ModelResource):
|
||||||
if 'blog_post' in bundle.data:
|
if 'blog_post' in bundle.data:
|
||||||
bundle = self._clean_publish_date(bundle)
|
bundle = self._clean_publish_date(bundle)
|
||||||
|
|
||||||
return super(PrivateSniptResource, self).obj_update(bundle,
|
return super(PrivateSniptResource, self) \
|
||||||
user=bundle.request.user, **kwargs)
|
.obj_update(bundle,
|
||||||
|
user=bundle.request.user, **kwargs)
|
||||||
|
|
||||||
def _clean_publish_date(self, bundle):
|
def _clean_publish_date(self, bundle):
|
||||||
if bundle.data['blog_post'] and 'publish_date' not in bundle.data:
|
if bundle.data['blog_post'] and 'publish_date' not in bundle.data:
|
||||||
|
@ -407,6 +442,7 @@ class PrivateSniptResource(ModelResource):
|
||||||
else:
|
else:
|
||||||
bundle.obj.tags.set()
|
bundle.obj.tags.set()
|
||||||
|
|
||||||
|
|
||||||
class PrivateFavoriteResource(ModelResource):
|
class PrivateFavoriteResource(ModelResource):
|
||||||
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
|
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
|
||||||
snipt = fields.ForeignKey(PrivateSniptResource, 'snipt', full=False)
|
snipt = fields.ForeignKey(PrivateSniptResource, 'snipt', full=False)
|
||||||
|
@ -414,24 +450,24 @@ class PrivateFavoriteResource(ModelResource):
|
||||||
class Meta:
|
class Meta:
|
||||||
queryset = Favorite.objects.all().order_by('-created')
|
queryset = Favorite.objects.all().order_by('-created')
|
||||||
resource_name = 'favorite'
|
resource_name = 'favorite'
|
||||||
fields = ['id',]
|
fields = ['id']
|
||||||
validation = FavoriteValidation()
|
validation = FavoriteValidation()
|
||||||
detail_allowed_methods = ['get', 'post', 'delete']
|
detail_allowed_methods = ['get', 'post', 'delete']
|
||||||
list_allowed_methods = ['get', 'post',]
|
list_allowed_methods = ['get', 'post']
|
||||||
authentication = ApiKeyAuthentication()
|
authentication = ApiKeyAuthentication()
|
||||||
authorization = PrivateFavoriteAuthorization()
|
authorization = PrivateFavoriteAuthorization()
|
||||||
ordering = ['created',]
|
ordering = ['created']
|
||||||
always_return_data = True
|
always_return_data = True
|
||||||
max_limit = 200
|
max_limit = 200
|
||||||
cache = SimpleCache()
|
cache = SimpleCache()
|
||||||
|
|
||||||
def dehydrate(self, bundle):
|
def dehydrate(self, bundle):
|
||||||
bundle.data['snipt'] = '/api/public/snipt/{}/'.format(
|
bundle.data['snipt'] = '/api/public/snipt/{}/'.format(
|
||||||
bundle.obj.snipt.pk)
|
bundle.obj.snipt.pk)
|
||||||
return bundle
|
return bundle
|
||||||
|
|
||||||
def obj_create(self, bundle, **kwargs):
|
def obj_create(self, bundle, **kwargs):
|
||||||
bundle.data['user'] = bundle.request.user
|
bundle.data['user'] = bundle.request.user
|
||||||
bundle.data['snipt'] = Snipt.objects.get(pk=bundle.data['snipt'])
|
bundle.data['snipt'] = Snipt.objects.get(pk=bundle.data['snipt'])
|
||||||
return super(PrivateFavoriteResource, self).obj_create(bundle,
|
return super(PrivateFavoriteResource, self) \
|
||||||
user=bundle.request.user, **kwargs)
|
.obj_create(bundle, user=bundle.request.user, **kwargs)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
from snipts.models import Snipt
|
from snipts.models import Snipt
|
||||||
|
|
||||||
|
|
||||||
class SniptForm(ModelForm):
|
class SniptForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Snipt
|
model = Snipt
|
||||||
|
|
151
snipts/models.py
151
snipts/models.py
|
@ -15,36 +15,40 @@ from pygments.formatters import HtmlFormatter
|
||||||
|
|
||||||
from snipts.utils import slugify_uniquely
|
from snipts.utils import slugify_uniquely
|
||||||
|
|
||||||
import datetime, hashlib, random, re
|
import datetime
|
||||||
|
import hashlib
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
class Snipt(models.Model):
|
class Snipt(models.Model):
|
||||||
"""An individual Snipt."""
|
"""An individual Snipt."""
|
||||||
|
|
||||||
user = models.ForeignKey(User, blank=True, null=True)
|
user = models.ForeignKey(User, blank=True, null=True)
|
||||||
|
|
||||||
title = models.CharField(max_length=255, blank=True, null=True, default='Untitled')
|
title = models.CharField(max_length=255, blank=True, null=True,
|
||||||
slug = models.SlugField(max_length=255, blank=True)
|
default='Untitled')
|
||||||
custom_slug = models.SlugField(max_length=255, blank=True)
|
slug = models.SlugField(max_length=255, blank=True)
|
||||||
tags = TaggableManager()
|
custom_slug = models.SlugField(max_length=255, blank=True)
|
||||||
|
tags = TaggableManager()
|
||||||
|
|
||||||
lexer = models.CharField(max_length=50)
|
lexer = models.CharField(max_length=50)
|
||||||
code = models.TextField()
|
code = models.TextField()
|
||||||
meta = models.TextField(blank=True, null=True)
|
meta = models.TextField(blank=True, null=True)
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
stylized = models.TextField(blank=True, null=True)
|
stylized = models.TextField(blank=True, null=True)
|
||||||
stylized_min = models.TextField(blank=True, null=True)
|
stylized_min = models.TextField(blank=True, null=True)
|
||||||
embedded = models.TextField(blank=True, null=True)
|
embedded = models.TextField(blank=True, null=True)
|
||||||
line_count = models.IntegerField(blank=True, null=True, default=None)
|
line_count = models.IntegerField(blank=True, null=True, default=None)
|
||||||
|
|
||||||
key = models.CharField(max_length=100, blank=True, null=True)
|
key = models.CharField(max_length=100, blank=True, null=True)
|
||||||
public = models.BooleanField(default=False)
|
public = models.BooleanField(default=False)
|
||||||
blog_post = models.BooleanField(default=False)
|
blog_post = models.BooleanField(default=False)
|
||||||
|
|
||||||
views = models.IntegerField(default=0)
|
views = models.IntegerField(default=0)
|
||||||
|
|
||||||
created = models.DateTimeField(auto_now_add=True, editable=False)
|
created = models.DateTimeField(auto_now_add=True, editable=False)
|
||||||
modified = models.DateTimeField(auto_now=True, editable=False)
|
modified = models.DateTimeField(auto_now=True, editable=False)
|
||||||
publish_date = models.DateTimeField(blank=True, null=True)
|
publish_date = models.DateTimeField(blank=True, null=True)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
@ -53,7 +57,9 @@ class Snipt(models.Model):
|
||||||
self.slug = slugify_uniquely(self.title, Snipt)
|
self.slug = slugify_uniquely(self.title, Snipt)
|
||||||
|
|
||||||
if not self.key:
|
if not self.key:
|
||||||
self.key = hashlib.md5(self.slug + str(datetime.datetime.now()) + str(random.random())).hexdigest()
|
self.key = hashlib.md5(self.slug +
|
||||||
|
str(datetime.datetime.now()) +
|
||||||
|
str(random.random())).hexdigest()
|
||||||
|
|
||||||
if self.lexer == 'markdown':
|
if self.lexer == 'markdown':
|
||||||
self.stylized = markdown(self.code, 'default')
|
self.stylized = markdown(self.code, 'default')
|
||||||
|
@ -61,21 +67,46 @@ class Snipt(models.Model):
|
||||||
# Snipt embeds
|
# Snipt embeds
|
||||||
for match in re.findall('\[\[(\w{32})\]\]', self.stylized):
|
for match in re.findall('\[\[(\w{32})\]\]', self.stylized):
|
||||||
self.stylized = self.stylized.replace('[[' + str(match) + ']]',
|
self.stylized = self.stylized.replace('[[' + str(match) + ']]',
|
||||||
'<script type="text/javascript" src="https://snipt.net/embed/{}/?snipt"></script><div id="snipt-embed-{}"></div>'.format(match, match))
|
"""
|
||||||
|
<script type="text/javascript"
|
||||||
|
src="https://snipt.net/embed/{}/?snipt">
|
||||||
|
</script>
|
||||||
|
<div id="snipt-embed-{}"></div>""".format(match, match))
|
||||||
|
|
||||||
# YouTube embeds
|
# YouTube embeds
|
||||||
for match in re.findall('\[\[youtube-(\w{11})\-(\d+)x(\d+)\]\]', self.stylized):
|
for match in re.findall('\[\[youtube-(\w{11})\-(\d+)x(\d+)\]\]',
|
||||||
self.stylized = self.stylized.replace('[[youtube-{}-{}x{}]]'.format(str(match[0]), str(match[1]), str(match[2])),
|
self.stylized):
|
||||||
'<iframe width="{}" height="{}" src="https://www.youtube.com/embed/{}" frameborder="0" allowfullscreen></iframe>'.format(match[1], match[2], match[0]))
|
self.stylized = self.stylized \
|
||||||
|
.replace('[[youtube-{}-{}x{}]]'.format(
|
||||||
|
str(match[0]),
|
||||||
|
str(match[1]),
|
||||||
|
str(match[2])),
|
||||||
|
"""<iframe width="{}" height="{}"
|
||||||
|
src="https://www.youtube.com/embed/{}"
|
||||||
|
frameborder="0" allowfullscreen></iframe>"""
|
||||||
|
.format(match[1], match[2], match[0]))
|
||||||
|
|
||||||
# Vimeo embeds
|
# Vimeo embeds
|
||||||
for match in re.findall('\[\[vimeo-(\d+)\-(\d+)x(\d+)\]\]', self.stylized):
|
for match in re.findall('\[\[vimeo-(\d+)\-(\d+)x(\d+)\]\]',
|
||||||
self.stylized = self.stylized.replace('[[vimeo-{}-{}x{}]]'.format(str(match[0]), str(match[1]), str(match[2])),
|
self.stylized):
|
||||||
'<iframe src="https://player.vimeo.com/video/{}" width="{}" height="{}" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'.format(match[0], match[1], match[2]))
|
self.stylized = self.stylized \
|
||||||
|
.replace('[[vimeo-{}-{}x{}]]'.format(
|
||||||
|
str(match[0]),
|
||||||
|
str(match[1]),
|
||||||
|
str(match[2])),
|
||||||
|
"""<iframe src="https://player.vimeo.com/video/{}"
|
||||||
|
width="{}" height="{}" frameborder="0"
|
||||||
|
webkitAllowFullScreen mozallowfullscreen
|
||||||
|
allowFullScreen></iframe>"""
|
||||||
|
.format(match[0], match[1], match[2]))
|
||||||
|
|
||||||
# Tweet embeds
|
# Tweet embeds
|
||||||
for match in re.findall('\[\[tweet-(\d+)\]\]', self.stylized):
|
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)))
|
self.stylized = self.stylized \
|
||||||
|
.replace(
|
||||||
|
'[[tweet-{}]]'.format(str(match)),
|
||||||
|
'<div class="embedded-tweet" data-tweet-id="{}"></div>'
|
||||||
|
.format(str(match)))
|
||||||
|
|
||||||
# Parse Snipt usernames
|
# Parse Snipt usernames
|
||||||
for match in re.findall('@(\w+) ', self.stylized):
|
for match in re.findall('@(\w+) ', self.stylized):
|
||||||
|
@ -85,17 +116,19 @@ class Snipt(models.Model):
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
url = user.profile.get_user_profile_url()
|
url = user.profile.get_user_profile_url()
|
||||||
self.stylized = self.stylized.replace('@{} '.format(str(match)), '<a href="{}">@{}</a> '.format(url, match))
|
self.stylized = self.stylized \
|
||||||
|
.replace('@{} '.format(str(match)),
|
||||||
|
'<a href="{}">@{}</a> '.format(url, match))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.stylized = highlight(self.code,
|
self.stylized = highlight(self.code,
|
||||||
get_lexer_by_name(self.lexer, encoding='UTF-8'),
|
get_lexer_by_name(self.lexer,
|
||||||
|
encoding='UTF-8'),
|
||||||
HtmlFormatter(linenos='table',
|
HtmlFormatter(linenos='table',
|
||||||
anchorlinenos=True,
|
anchorlinenos=True,
|
||||||
lineanchors='L',
|
lineanchors='L',
|
||||||
linespans='L',
|
linespans='L',
|
||||||
)
|
))
|
||||||
)
|
|
||||||
self.line_count = len(self.code.split('\n'))
|
self.line_count = len(self.code.split('\n'))
|
||||||
|
|
||||||
if self.lexer == 'markdown':
|
if self.lexer == 'markdown':
|
||||||
|
@ -104,7 +137,8 @@ class Snipt(models.Model):
|
||||||
lexer_for_embedded = self.lexer
|
lexer_for_embedded = self.lexer
|
||||||
|
|
||||||
embedded = highlight(self.code,
|
embedded = highlight(self.code,
|
||||||
get_lexer_by_name(lexer_for_embedded, encoding='UTF-8'),
|
get_lexer_by_name(lexer_for_embedded,
|
||||||
|
encoding='UTF-8'),
|
||||||
HtmlFormatter(
|
HtmlFormatter(
|
||||||
style='native',
|
style='native',
|
||||||
noclasses=True,
|
noclasses=True,
|
||||||
|
@ -120,8 +154,8 @@ class Snipt(models.Model):
|
||||||
-webkit-border-radius: 5px;
|
-webkit-border-radius: 5px;
|
||||||
-moz-border-radius: 5px;
|
-moz-border-radius: 5px;
|
||||||
"""))
|
"""))
|
||||||
embedded = (embedded.replace("\\\"","\\\\\"")
|
embedded = (embedded.replace("\\\"", "\\\\\"")
|
||||||
.replace('\'','\\\'')
|
.replace('\'', '\\\'')
|
||||||
.replace("\\", "\\\\")
|
.replace("\\", "\\\\")
|
||||||
.replace('background: #202020', ''))
|
.replace('background: #202020', ''))
|
||||||
self.embedded = embedded
|
self.embedded = embedded
|
||||||
|
@ -139,18 +173,23 @@ class Snipt(models.Model):
|
||||||
if self.lexer == 'markdown':
|
if self.lexer == 'markdown':
|
||||||
self.stylized_min = markdown(self.code[:1000], 'default')
|
self.stylized_min = markdown(self.code[:1000], 'default')
|
||||||
else:
|
else:
|
||||||
self.stylized_min = highlight(self.code[:1000],
|
self.stylized_min = highlight(
|
||||||
get_lexer_by_name(self.lexer, encoding='UTF-8'),
|
self.code[:1000],
|
||||||
HtmlFormatter(linenos='table', linenospecial=1, lineanchors='line'))
|
get_lexer_by_name(self.lexer, encoding='UTF-8'),
|
||||||
|
HtmlFormatter(linenos='table',
|
||||||
|
linenospecial=1,
|
||||||
|
lineanchors='line'))
|
||||||
return self.stylized_min
|
return self.stylized_min
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
|
|
||||||
if self.blog_post:
|
if self.blog_post:
|
||||||
if self.user.profile.blog_domain:
|
if self.user.profile.blog_domain:
|
||||||
return u'http://{}/{}/'.format(self.user.profile.blog_domain.split(' ')[0], self.slug)
|
return u'http://{}/{}/'.format(
|
||||||
|
self.user.profile.blog_domain.split(' ')[0], self.slug)
|
||||||
else:
|
else:
|
||||||
return u'https://{}.snipt.net/{}/'.format(self.user.username.replace('_', '-'), self.slug)
|
return u'https://{}.snipt.net/{}/'.format(
|
||||||
|
self.user.username.replace('_', '-'), self.slug)
|
||||||
|
|
||||||
if self.custom_slug:
|
if self.custom_slug:
|
||||||
return u'/{}/'.format(self.custom_slug)
|
return u'/{}/'.format(self.custom_slug)
|
||||||
|
@ -158,15 +197,18 @@ class Snipt(models.Model):
|
||||||
if self.public:
|
if self.public:
|
||||||
return u'/{}/{}/'.format(self.user.username, self.slug)
|
return u'/{}/{}/'.format(self.user.username, self.slug)
|
||||||
else:
|
else:
|
||||||
return u'/{}/{}/?key={}'.format(self.user.username, self.slug, self.key)
|
return u'/{}/{}/?key={}'.format(
|
||||||
|
self.user.username, self.slug, self.key)
|
||||||
|
|
||||||
def get_full_absolute_url(self):
|
def get_full_absolute_url(self):
|
||||||
|
|
||||||
if self.blog_post:
|
if self.blog_post:
|
||||||
if self.user.profile.blog_domain:
|
if self.user.profile.blog_domain:
|
||||||
return u'http://{}/{}/'.format(self.user.profile.blog_domain.split(' ')[0], self.slug)
|
return u'http://{}/{}/'.format(
|
||||||
|
self.user.profile.blog_domain.split(' ')[0], self.slug)
|
||||||
else:
|
else:
|
||||||
return u'https://{}.snipt.net/{}/'.format(self.user.username, self.slug)
|
return u'https://{}.snipt.net/{}/'.format(
|
||||||
|
self.user.username, self.slug)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
root = 'http://local.snipt.net'
|
root = 'http://local.snipt.net'
|
||||||
|
@ -176,7 +218,10 @@ class Snipt(models.Model):
|
||||||
if self.public:
|
if self.public:
|
||||||
return u'{}/{}/{}/'.format(root, self.user.username, self.slug)
|
return u'{}/{}/{}/'.format(root, self.user.username, self.slug)
|
||||||
else:
|
else:
|
||||||
return u'{}/{}/{}/?key={}'.format(root, self.user.username, self.slug, self.key)
|
return u'{}/{}/{}/?key={}'.format(root,
|
||||||
|
self.user.username,
|
||||||
|
self.slug,
|
||||||
|
self.key)
|
||||||
|
|
||||||
def get_download_url(self):
|
def get_download_url(self):
|
||||||
|
|
||||||
|
@ -233,12 +278,14 @@ class Snipt(models.Model):
|
||||||
else:
|
else:
|
||||||
return get_lexer_by_name(self.lexer).name
|
return get_lexer_by_name(self.lexer).name
|
||||||
|
|
||||||
|
|
||||||
class Favorite(models.Model):
|
class Favorite(models.Model):
|
||||||
snipt = models.ForeignKey(Snipt)
|
snipt = models.ForeignKey(Snipt)
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
|
|
||||||
created = models.DateTimeField(auto_now_add=True, editable=False)
|
created = models.DateTimeField(auto_now_add=True, editable=False)
|
||||||
modified = models.DateTimeField(auto_now=True, editable=False)
|
modified = models.DateTimeField(auto_now=True, editable=False)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'{} favorited by {}'.format(self.snipt.title, self.user.username)
|
return u'{} favorited by {}'.format(self.snipt.title,
|
||||||
|
self.user.username)
|
||||||
|
|
|
@ -15,4 +15,5 @@ class SniptIndex(indexes.SearchIndex, indexes.Indexable):
|
||||||
|
|
||||||
def index_queryset(self, **kwargs):
|
def index_queryset(self, **kwargs):
|
||||||
"""Used when the entire index for model is updated."""
|
"""Used when the entire index for model is updated."""
|
||||||
return self.get_model().objects.filter(created__lte=datetime.datetime.now())
|
return self.get_model().objects.filter(
|
||||||
|
created__lte=datetime.datetime.now())
|
||||||
|
|
|
@ -11,6 +11,7 @@ import hashlib
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@tag(register, [Constant('as'), Variable()])
|
@tag(register, [Constant('as'), Variable()])
|
||||||
def snipt_is_favorited_by_user(context, asvar):
|
def snipt_is_favorited_by_user(context, asvar):
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ def snipt_is_favorited_by_user(context, asvar):
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
@tag(register, [])
|
@tag(register, [])
|
||||||
def snipts_count_for_user(context):
|
def snipts_count_for_user(context):
|
||||||
|
|
||||||
|
@ -42,11 +44,13 @@ def snipts_count_for_user(context):
|
||||||
|
|
||||||
return snipts
|
return snipts
|
||||||
|
|
||||||
|
|
||||||
@tag(register, [Constant('as'), Variable()])
|
@tag(register, [Constant('as'), Variable()])
|
||||||
def get_lexers(context, asvar):
|
def get_lexers(context, asvar):
|
||||||
context[asvar] = get_lexers_list()
|
context[asvar] = get_lexers_list()
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
@tag(register, [Constant('for'), Variable()])
|
@tag(register, [Constant('for'), Variable()])
|
||||||
def generate_line_numbers(context, line_numbers):
|
def generate_line_numbers(context, line_numbers):
|
||||||
html = ''
|
html = ''
|
||||||
|
@ -56,6 +60,7 @@ def generate_line_numbers(context, line_numbers):
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def md5(string):
|
def md5(string):
|
||||||
return hashlib.md5(string.lower()).hexdigest()
|
return hashlib.md5(string.lower()).hexdigest()
|
||||||
|
|
|
@ -11,11 +11,19 @@ class SniptResourceTest(ResourceTestCase):
|
||||||
super(SniptResourceTest, self).setUp()
|
super(SniptResourceTest, self).setUp()
|
||||||
|
|
||||||
# Johnny
|
# Johnny
|
||||||
self.johnny = User.objects.create_user('johnny', 'johnny@snipt.net', 'password')
|
self.johnny = User.objects.create_user('johnny', 'johnny@snipt.net',
|
||||||
|
'password')
|
||||||
ApiKey.objects.get_or_create(user=self.johnny)
|
ApiKey.objects.get_or_create(user=self.johnny)
|
||||||
self.johnny_auth = self.create_apikey(self.johnny, self.johnny.api_key.key)
|
self.johnny_auth = self.create_apikey(self.johnny,
|
||||||
self.johnny_private = Snipt(title='Private snipt for Johnny', lexer='text', public=False, user=self.johnny)
|
self.johnny.api_key.key)
|
||||||
self.johnny_public = Snipt(title='Public snipt for Johnny', lexer='text', public=True, user=self.johnny)
|
self.johnny_private = Snipt(title='Private snipt for Johnny',
|
||||||
|
lexer='text',
|
||||||
|
public=False,
|
||||||
|
user=self.johnny)
|
||||||
|
self.johnny_public = Snipt(title='Public snipt for Johnny',
|
||||||
|
lexer='text',
|
||||||
|
public=True,
|
||||||
|
user=self.johnny)
|
||||||
self.johnny_private.save()
|
self.johnny_private.save()
|
||||||
self.johnny_public.save()
|
self.johnny_public.save()
|
||||||
|
|
||||||
|
@ -23,16 +31,21 @@ class SniptResourceTest(ResourceTestCase):
|
||||||
self.bob = User.objects.create_user('bob', 'bob@snipt.net', 'password')
|
self.bob = User.objects.create_user('bob', 'bob@snipt.net', 'password')
|
||||||
ApiKey.objects.get_or_create(user=self.bob)
|
ApiKey.objects.get_or_create(user=self.bob)
|
||||||
self.bob_auth = self.create_apikey(self.bob, self.bob.api_key.key)
|
self.bob_auth = self.create_apikey(self.bob, self.bob.api_key.key)
|
||||||
self.bob_private = Snipt(title='Private snipt for Bob', lexer='text', public=False, user=self.bob)
|
self.bob_private = Snipt(title='Private snipt for Bob',
|
||||||
self.bob_public = Snipt(title='Public snipt for Bob', lexer='text', public=True, user=self.bob)
|
lexer='text',
|
||||||
|
public=False,
|
||||||
|
user=self.bob)
|
||||||
|
self.bob_public = Snipt(title='Public snipt for Bob',
|
||||||
|
lexer='text',
|
||||||
|
public=True,
|
||||||
|
user=self.bob)
|
||||||
self.bob_private.save()
|
self.bob_private.save()
|
||||||
self.bob_public.save()
|
self.bob_public.save()
|
||||||
|
|
||||||
|
|
||||||
# Private
|
|
||||||
def test_get_private_list(self):
|
def test_get_private_list(self):
|
||||||
|
|
||||||
resp = self.api_client.get('/api/private/snipt/', format='json', authentication=self.johnny_auth)
|
resp = self.api_client.get('/api/private/snipt/', format='json',
|
||||||
|
authentication=self.johnny_auth)
|
||||||
|
|
||||||
self.assertHttpOK(resp)
|
self.assertHttpOK(resp)
|
||||||
self.assertValidJSONResponse(resp)
|
self.assertValidJSONResponse(resp)
|
||||||
|
@ -40,18 +53,27 @@ class SniptResourceTest(ResourceTestCase):
|
||||||
|
|
||||||
def test_get_private_detail(self):
|
def test_get_private_detail(self):
|
||||||
|
|
||||||
resp = self.api_client.get('/api/private/snipt/{}/'.format(self.johnny_private.pk), format='json', authentication=self.johnny_auth)
|
resp = self.api_client.get(
|
||||||
|
'/api/private/snipt/{}/'.format(self.johnny_private.pk),
|
||||||
|
format='json',
|
||||||
|
authentication=self.johnny_auth)
|
||||||
|
|
||||||
self.assertHttpOK(resp)
|
self.assertHttpOK(resp)
|
||||||
self.assertValidJSONResponse(resp)
|
self.assertValidJSONResponse(resp)
|
||||||
self.assertEqual(self.deserialize(resp)['key'], self.johnny_private.key)
|
self.assertEqual(self.deserialize(resp)['key'],
|
||||||
|
self.johnny_private.key)
|
||||||
|
|
||||||
# Unauthenticated request.
|
# Unauthenticated request.
|
||||||
resp = self.api_client.get('/api/private/snipt/{}/'.format(self.johnny_private.pk), format='json')
|
resp = self.api_client.get(
|
||||||
|
'/api/private/snipt/{}/'.format(self.johnny_private.pk),
|
||||||
|
format='json')
|
||||||
self.assertHttpUnauthorized(resp)
|
self.assertHttpUnauthorized(resp)
|
||||||
|
|
||||||
# Unauthorized request.
|
# Unauthorized request.
|
||||||
resp = self.api_client.get('/api/private/snipt/{}/'.format(self.johnny_private.pk), format='json', authentication=self.bob_auth)
|
resp = self.api_client.get(
|
||||||
|
'/api/private/snipt/{}/'.format(self.johnny_private.pk),
|
||||||
|
format='json',
|
||||||
|
authentication=self.bob_auth)
|
||||||
self.assertHttpUnauthorized(resp)
|
self.assertHttpUnauthorized(resp)
|
||||||
|
|
||||||
def test_post_private_list(self):
|
def test_post_private_list(self):
|
||||||
|
@ -63,21 +85,21 @@ class SniptResourceTest(ResourceTestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.api_client.post('/api/private/snipt/',
|
resp = self.api_client.post('/api/private/snipt/',
|
||||||
data=new_snipt,
|
data=new_snipt,
|
||||||
format='json',
|
format='json',
|
||||||
authentication=self.johnny_auth)
|
authentication=self.johnny_auth)
|
||||||
|
|
||||||
self.assertHttpCreated(resp)
|
self.assertHttpCreated(resp)
|
||||||
self.assertEqual(Snipt.objects.count(), 5)
|
self.assertEqual(Snipt.objects.count(), 5)
|
||||||
|
|
||||||
resp = self.api_client.get('/api/private/snipt/', format='json', authentication=self.johnny_auth)
|
resp = self.api_client.get('/api/private/snipt/',
|
||||||
|
format='json',
|
||||||
|
authentication=self.johnny_auth)
|
||||||
self.assertEqual(len(self.deserialize(resp)['objects']), 3)
|
self.assertEqual(len(self.deserialize(resp)['objects']), 3)
|
||||||
|
|
||||||
resp = self.api_client.get('/api/public/snipt/', format='json')
|
resp = self.api_client.get('/api/public/snipt/', format='json')
|
||||||
self.assertEqual(len(self.deserialize(resp)['objects']), 2)
|
self.assertEqual(len(self.deserialize(resp)['objects']), 2)
|
||||||
|
|
||||||
|
|
||||||
# Public
|
|
||||||
def test_get_public_list(self):
|
def test_get_public_list(self):
|
||||||
|
|
||||||
self.assertEqual(Snipt.objects.count(), 4)
|
self.assertEqual(Snipt.objects.count(), 4)
|
||||||
|
|
|
@ -3,23 +3,46 @@ from django.conf.urls import *
|
||||||
from snipts import views
|
from snipts import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = \
|
||||||
|
patterns('',
|
||||||
# Redirects
|
url(r'^s/(?P<snipt_key>[^/]+)/(?P<lexer>[^\?]+)?$',
|
||||||
url(r'^s/(?P<snipt_key>[^/]+)/(?P<lexer>[^\?]+)?$', views.redirect_snipt, name='redirect-snipt'),
|
views.redirect_snipt, name='redirect-snipt'),
|
||||||
url(r'^(?P<username>[^/]+)/feed/$', views.redirect_user_feed, name='redirect-feed'),
|
url(r'^(?P<username>[^/]+)/feed/$',
|
||||||
url(r'^public/tag/(?P<tag_slug>[^/]+)/feed/$', views.redirect_public_tag_feed, name='redirect-public-tag-feed'),
|
views.redirect_user_feed,
|
||||||
url(r'^(?P<username>[^/]+)/tag/(?P<tag_slug>[^/]+)/feed/$', views.redirect_user_tag_feed, name='redirect-user-tag-feed'),
|
name='redirect-feed'),
|
||||||
|
url(r'^public/tag/(?P<tag_slug>[^/]+)/feed/$',
|
||||||
url(r'^public/$', views.list_public, name='list-public'),
|
views.redirect_public_tag_feed,
|
||||||
url(r'^public/tag/(?P<tag_slug>[^/]+)/$', views.list_public, name='list-public-tag'),
|
name='redirect-public-tag-feed'),
|
||||||
url(r'^download/(?P<snipt_key>[^/]+).*$', views.download, name='download'),
|
url(r'^(?P<username>[^/]+)/tag/(?P<tag_slug>[^/]+)/feed/$',
|
||||||
url(r'^embed/(?P<snipt_key>[^/]+)/$', views.embed, name='embed'),
|
views.redirect_user_tag_feed,
|
||||||
url(r'^raw/(?P<snipt_key>[^/]+)/(?P<lexer>[^\?]+)?$', views.raw, name='raw'),
|
name='redirect-user-tag-feed'),
|
||||||
url(r'^(?P<username_or_custom_slug>[^/]+)/$', views.list_user, name='list-user'),
|
url(r'^public/$',
|
||||||
url(r'^(?P<username_or_custom_slug>[^/]+)/tag/(?P<tag_slug>[^/]+)/$', views.list_user, name='list-user-tag'),
|
views.list_public,
|
||||||
url(r'^(?P<username>[^/]+)/favorites/$', views.favorites, name='favorites'),
|
name='list-public'),
|
||||||
url(r'^(?P<username>[^/]+)/blog-posts/$', views.blog_posts, name='blog-posts'),
|
url(r'^public/tag/(?P<tag_slug>[^/]+)/$',
|
||||||
url(r'^(?P<username>[^/]+)/(?P<snipt_slug>[^/]+)/$', views.detail, name='detail'),
|
views.list_public,
|
||||||
|
name='list-public-tag'),
|
||||||
)
|
url(r'^download/(?P<snipt_key>[^/]+).*$',
|
||||||
|
views.download,
|
||||||
|
name='download'),
|
||||||
|
url(r'^embed/(?P<snipt_key>[^/]+)/$',
|
||||||
|
views.embed,
|
||||||
|
name='embed'),
|
||||||
|
url(r'^raw/(?P<snipt_key>[^/]+)/(?P<lexer>[^\?]+)?$',
|
||||||
|
views.raw,
|
||||||
|
name='raw'),
|
||||||
|
url(r'^(?P<username_or_custom_slug>[^/]+)/$',
|
||||||
|
views.list_user,
|
||||||
|
name='list-user'),
|
||||||
|
url(r'^(?P<username_or_custom_slug>[^/]+)/tag/(?P<tag_slug>[^/]+)/$',
|
||||||
|
views.list_user,
|
||||||
|
name='list-user-tag'),
|
||||||
|
url(r'^(?P<username>[^/]+)/favorites/$',
|
||||||
|
views.favorites,
|
||||||
|
name='favorites'),
|
||||||
|
url(r'^(?P<username>[^/]+)/blog-posts/$',
|
||||||
|
views.blog_posts,
|
||||||
|
name='blog-posts'),
|
||||||
|
url(r'^(?P<username>[^/]+)/(?P<snipt_slug>[^/]+)/$',
|
||||||
|
views.detail,
|
||||||
|
name='detail'))
|
||||||
|
|
|
@ -17,6 +17,7 @@ def slugify_uniquely(value, model, slugfield="slug"):
|
||||||
return potential
|
return potential
|
||||||
suffix = str(uuid.uuid4()).split('-')[0]
|
suffix = str(uuid.uuid4()).split('-')[0]
|
||||||
|
|
||||||
|
|
||||||
def activate_user(user, request, **kwargs):
|
def activate_user(user, request, **kwargs):
|
||||||
user.is_active = True
|
user.is_active = True
|
||||||
user.save()
|
user.save()
|
||||||
|
@ -25,6 +26,7 @@ def activate_user(user, request, **kwargs):
|
||||||
password=request.POST['password1'])
|
password=request.POST['password1'])
|
||||||
login(request, user)
|
login(request, user)
|
||||||
|
|
||||||
|
|
||||||
def get_lexers_list():
|
def get_lexers_list():
|
||||||
lexers = list(get_all_lexers())
|
lexers = list(get_all_lexers())
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,12 @@ def detail(request, username, snipt_slug):
|
||||||
'user': user,
|
'user': user,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def download(request, snipt_key):
|
def download(request, snipt_key):
|
||||||
snipt = get_object_or_404(Snipt, key=snipt_key)
|
snipt = get_object_or_404(Snipt, key=snipt_key)
|
||||||
return HttpResponse(snipt.code, content_type='application/x-download')
|
return HttpResponse(snipt.code, content_type='application/x-download')
|
||||||
|
|
||||||
|
|
||||||
def embed(request, snipt_key):
|
def embed(request, snipt_key):
|
||||||
snipt = get_object_or_404(Snipt, key=snipt_key)
|
snipt = get_object_or_404(Snipt, key=snipt_key)
|
||||||
|
|
||||||
|
@ -75,6 +77,7 @@ def embed(request, snipt_key):
|
||||||
context_instance=RequestContext(request),
|
context_instance=RequestContext(request),
|
||||||
content_type='application/javascript')
|
content_type='application/javascript')
|
||||||
|
|
||||||
|
|
||||||
@render_to('snipts/list-user.html')
|
@render_to('snipts/list-user.html')
|
||||||
def blog_posts(request, username):
|
def blog_posts(request, username):
|
||||||
|
|
||||||
|
@ -92,7 +95,8 @@ def blog_posts(request, username):
|
||||||
public_user = True
|
public_user = True
|
||||||
user = get_object_or_404(User, username=username)
|
user = get_object_or_404(User, username=username)
|
||||||
snipts = Snipt.objects.filter(blog_post=True, user=user, public=True)
|
snipts = Snipt.objects.filter(blog_post=True, user=user, public=True)
|
||||||
tags = Tag.objects.filter(snipt__user=user, snipt__public=True).distinct()
|
tags = Tag.objects.filter(snipt__user=user,
|
||||||
|
snipt__public=True).distinct()
|
||||||
|
|
||||||
tags = tags.order_by('name')
|
tags = tags.order_by('name')
|
||||||
snipts = snipts.order_by('-created')
|
snipts = snipts.order_by('-created')
|
||||||
|
@ -112,6 +116,7 @@ def blog_posts(request, username):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@render_to('snipts/list-user.html')
|
@render_to('snipts/list-user.html')
|
||||||
def favorites(request, username):
|
def favorites(request, username):
|
||||||
|
|
||||||
|
@ -148,6 +153,7 @@ def favorites(request, username):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@render_to('snipts/list-public.html')
|
@render_to('snipts/list-public.html')
|
||||||
def list_public(request, tag_slug=None):
|
def list_public(request, tag_slug=None):
|
||||||
|
|
||||||
|
@ -175,6 +181,7 @@ def list_public(request, tag_slug=None):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@render_to('snipts/list-user.html')
|
@render_to('snipts/list-user.html')
|
||||||
def list_user(request, username_or_custom_slug, tag_slug=None):
|
def list_user(request, username_or_custom_slug, tag_slug=None):
|
||||||
|
|
||||||
|
@ -190,7 +197,8 @@ def list_user(request, username_or_custom_slug, tag_slug=None):
|
||||||
tags = Tag.objects
|
tags = Tag.objects
|
||||||
snipts = Snipt.objects
|
snipts = Snipt.objects
|
||||||
|
|
||||||
if user == request.user or (request.GET.get('api_key') == user.api_key.key):
|
if user == request.user or \
|
||||||
|
(request.GET.get('api_key') == user.api_key.key):
|
||||||
public = False
|
public = False
|
||||||
|
|
||||||
favorites = Favorite.objects.filter(user=user).values('snipt')
|
favorites = Favorite.objects.filter(user=user).values('snipt')
|
||||||
|
@ -232,6 +240,7 @@ def list_user(request, username_or_custom_slug, tag_slug=None):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
def raw(request, snipt_key, lexer=None):
|
def raw(request, snipt_key, lexer=None):
|
||||||
snipt = get_object_or_404(Snipt, key=snipt_key)
|
snipt = get_object_or_404(Snipt, key=snipt_key)
|
||||||
|
|
||||||
|
@ -250,23 +259,23 @@ def raw(request, snipt_key, lexer=None):
|
||||||
snipt.lexer = lexer
|
snipt.lexer = lexer
|
||||||
snipt.save()
|
snipt.save()
|
||||||
|
|
||||||
content_type='text/plain'
|
content_type = 'text/plain'
|
||||||
|
|
||||||
if 'nice' in request.GET:
|
if 'nice' in request.GET:
|
||||||
content_type='text/html'
|
content_type = 'text/html'
|
||||||
|
|
||||||
return render_to_response('snipts/raw.html',
|
return render_to_response('snipts/raw.html',
|
||||||
{'snipt': snipt},
|
{'snipt': snipt},
|
||||||
context_instance=RequestContext(request),
|
context_instance=RequestContext(request),
|
||||||
content_type=content_type)
|
content_type=content_type)
|
||||||
|
|
||||||
|
|
||||||
def rss(request, context):
|
def rss(request, context):
|
||||||
return render_to_response(
|
return render_to_response('rss.xml',
|
||||||
'rss.xml',
|
context,
|
||||||
context,
|
context_instance=RequestContext(request),
|
||||||
context_instance=RequestContext(request),
|
content_type="application/rss+xml")
|
||||||
content_type="application/rss+xml"
|
|
||||||
)
|
|
||||||
|
|
||||||
def search(request, template='search/search.html', load_all=True,
|
def search(request, template='search/search.html', load_all=True,
|
||||||
form_class=ModelSearchForm, searchqueryset=None,
|
form_class=ModelSearchForm, searchqueryset=None,
|
||||||
|
@ -279,12 +288,18 @@ def search(request, template='search/search.html', load_all=True,
|
||||||
# We have a query.
|
# We have a query.
|
||||||
if request.GET.get('q'):
|
if request.GET.get('q'):
|
||||||
|
|
||||||
if request.user.is_authenticated() and '--mine' in request.GET.get('q'):
|
if request.user.is_authenticated() and '--mine' in \
|
||||||
searchqueryset = SearchQuerySet().filter(author=request.user).order_by('-pub_date')
|
request.GET.get('q'):
|
||||||
|
searchqueryset = SearchQuerySet().filter(author=request.user) \
|
||||||
|
.order_by('-pub_date')
|
||||||
else:
|
else:
|
||||||
searchqueryset = SearchQuerySet().filter(Q(public=True) | Q(author=request.user)).order_by('-pub_date')
|
searchqueryset = SearchQuerySet() \
|
||||||
|
.filter(Q(public=True) | Q(author=request.user)) \
|
||||||
|
.order_by('-pub_date')
|
||||||
|
|
||||||
form = ModelSearchForm(request.GET, searchqueryset=searchqueryset, load_all=load_all)
|
form = ModelSearchForm(request.GET,
|
||||||
|
searchqueryset=searchqueryset,
|
||||||
|
load_all=load_all)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
query = form.cleaned_data['q']
|
query = form.cleaned_data['q']
|
||||||
|
@ -314,19 +329,24 @@ def search(request, template='search/search.html', load_all=True,
|
||||||
if extra_context:
|
if extra_context:
|
||||||
context.update(extra_context)
|
context.update(extra_context)
|
||||||
|
|
||||||
return render_to_response(template, context, context_instance=context_class(request))
|
return render_to_response(template,
|
||||||
|
context,
|
||||||
|
context_instance=context_class(request))
|
||||||
|
|
||||||
|
|
||||||
def redirect_snipt(request, snipt_key, lexer=None):
|
def redirect_snipt(request, snipt_key, lexer=None):
|
||||||
snipt = get_object_or_404(Snipt, key=snipt_key)
|
snipt = get_object_or_404(Snipt, key=snipt_key)
|
||||||
return HttpResponseRedirect(snipt.get_absolute_url())
|
return HttpResponseRedirect(snipt.get_absolute_url())
|
||||||
|
|
||||||
|
|
||||||
def redirect_public_tag_feed(request, tag_slug):
|
def redirect_public_tag_feed(request, tag_slug):
|
||||||
return HttpResponseRedirect('/public/tag/{}/?rss'.format(tag_slug))
|
return HttpResponseRedirect('/public/tag/{}/?rss'.format(tag_slug))
|
||||||
|
|
||||||
|
|
||||||
def redirect_user_feed(request, username):
|
def redirect_user_feed(request, username):
|
||||||
user = get_object_or_404(User, username=username)
|
user = get_object_or_404(User, username=username)
|
||||||
return HttpResponseRedirect(user.get_absolute_url() + '?rss')
|
return HttpResponseRedirect(user.get_absolute_url() + '?rss')
|
||||||
|
|
||||||
|
|
||||||
def redirect_user_tag_feed(request, username, tag_slug):
|
def redirect_user_tag_feed(request, username, tag_slug):
|
||||||
return HttpResponseRedirect(u'/{}/tag/{}/?rss'.format(username, tag_slug))
|
return HttpResponseRedirect(u'/{}/tag/{}/?rss'.format(username, tag_slug))
|
||||||
|
|
|
@ -66,7 +66,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<script>
|
<script>
|
||||||
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"></' + 'script>')
|
|
||||||
window.ll = function() {};
|
window.ll = function() {};
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
73
urls.py
73
urls.py
|
@ -1,6 +1,4 @@
|
||||||
from django.conf import settings
|
|
||||||
from django.conf.urls import include, patterns, url
|
from django.conf.urls import include, patterns, url
|
||||||
from django.conf.urls.static import static
|
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
@ -11,11 +9,9 @@ from snipts.api import (PublicSniptResource,
|
||||||
from snipts.views import search
|
from snipts.views import search
|
||||||
from tastypie.api import Api
|
from tastypie.api import Api
|
||||||
from utils.views import SniptRegistrationView
|
from utils.views import SniptRegistrationView
|
||||||
from jobs.views import jobs, jobs_json
|
|
||||||
from views import (homepage, lexers, login_redirect, pro, sitemap, tags,
|
from views import (homepage, lexers, login_redirect, pro, sitemap, tags,
|
||||||
pro_complete, user_api_key, for_teams, for_teams_complete)
|
pro_complete, user_api_key, for_teams, for_teams_complete)
|
||||||
|
|
||||||
import admin as custom_admin
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,47 +28,56 @@ private_api.register(PrivateUserResource())
|
||||||
private_api.register(PrivateFavoriteResource())
|
private_api.register(PrivateFavoriteResource())
|
||||||
private_api.register(PrivateUserProfileResource())
|
private_api.register(PrivateUserProfileResource())
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = \
|
||||||
|
patterns('',
|
||||||
|
|
||||||
url(r'^$', homepage),
|
url(r'^$', homepage),
|
||||||
url(r'^login-redirect/$', login_redirect),
|
url(r'^login-redirect/$', login_redirect),
|
||||||
|
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
|
|
||||||
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
|
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
|
||||||
url(r'^500/$', TemplateView.as_view(template_name='500.html')),
|
url(r'^500/$', TemplateView.as_view(template_name='500.html')),
|
||||||
|
|
||||||
url(r'^robots.txt$', TemplateView.as_view(template_name='robots.txt')),
|
url(r'^robots.txt$',
|
||||||
url(r'^humans.txt$', TemplateView.as_view(template_name='humans.txt')),
|
TemplateView.as_view(template_name='robots.txt')),
|
||||||
url(r'^sitemap.xml$', sitemap),
|
url(r'^humans.txt$',
|
||||||
url(r'^tags/$', tags),
|
TemplateView.as_view(template_name='humans.txt')),
|
||||||
|
url(r'^sitemap.xml$', sitemap),
|
||||||
|
url(r'^tags/$', tags),
|
||||||
|
|
||||||
url(r'^pro/$', pro),
|
url(r'^pro/$', pro),
|
||||||
url(r'^pro/complete/$', pro_complete),
|
url(r'^pro/complete/$', pro_complete),
|
||||||
|
|
||||||
url(r'^for-teams/$', for_teams),
|
url(r'^for-teams/$', for_teams),
|
||||||
url(r'^for-teams/complete/$', for_teams_complete),
|
url(r'^for-teams/complete/$', for_teams_complete),
|
||||||
|
|
||||||
url(r'^account/', include('accounts.urls')),
|
url(r'^account/', include('accounts.urls')),
|
||||||
|
|
||||||
url(r'^api/public/lexer/$', lexers),
|
url(r'^api/public/lexer/$', lexers),
|
||||||
|
|
||||||
url(r'^api/private/key/$', user_api_key),
|
url(r'^api/private/key/$', user_api_key),
|
||||||
url(r'^api/', include(public_api.urls)),
|
url(r'^api/', include(public_api.urls)),
|
||||||
url(r'^api/', include(private_api.urls)),
|
url(r'^api/', include(private_api.urls)),
|
||||||
|
|
||||||
url(r'^search/$', search),
|
url(r'^search/$', search),
|
||||||
|
|
||||||
url(r'^register/$', lambda x: HttpResponseRedirect('/signup/')),
|
url(r'^register/$', lambda x: HttpResponseRedirect('/signup/')),
|
||||||
url(r'^signup/$', SniptRegistrationView.as_view(),
|
url(r'^signup/$', SniptRegistrationView.as_view(),
|
||||||
name='registration_register'),
|
name='registration_register'),
|
||||||
url(r'', include('registration.backends.default.urls')),
|
url(r'', include('registration.backends.default.urls')),
|
||||||
|
|
||||||
url(r'^', include('snipts.urls')),
|
url(r'^', include('snipts.urls')),
|
||||||
|
|
||||||
url(r'^(?P<path>favicon\.ico)$', 'django.views.static.serve', {'document_root': os.path.join(os.path.dirname(__file__), 'static/img')}),
|
url(r'^(?P<path>favicon\.ico)$', 'django.views.static.serve', {
|
||||||
)
|
'document_root': os.path.join(os.path.dirname(__file__),
|
||||||
|
'static/img')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns += patterns('',
|
urlpatterns += \
|
||||||
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': os.path.join(os.path.dirname(__file__), 'media')}),
|
patterns('',
|
||||||
)
|
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {
|
||||||
|
'document_root': os.path.join(os.path.dirname(__file__),
|
||||||
|
'media')
|
||||||
|
}))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
class EmailOrUsernameModelBackend(object):
|
class EmailOrUsernameModelBackend(object):
|
||||||
def authenticate(self, username=None, password=None):
|
def authenticate(self, username=None, password=None):
|
||||||
if '@' in username:
|
if '@' in username:
|
||||||
|
|
|
@ -3,21 +3,22 @@ from registration.forms import RegistrationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
|
||||||
class SniptRegistrationForm(RegistrationForm):
|
class SniptRegistrationForm(RegistrationForm):
|
||||||
"""
|
"""
|
||||||
Subclass of ``RegistrationForm`` which enforces uniqueness of
|
Subclass of ``RegistrationForm`` which enforces uniqueness of
|
||||||
email addresses and further restricts usernames.
|
email addresses and further restricts usernames.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def clean_username(self):
|
def clean_username(self):
|
||||||
"""
|
"""
|
||||||
Validate that the username is alphanumeric and is not already
|
Validate that the username is alphanumeric and is not already
|
||||||
in use.
|
in use.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
existing = User.objects.filter(username__iexact=self.cleaned_data['username'])
|
existing = User.objects.filter(
|
||||||
|
username__iexact=self.cleaned_data['username'])
|
||||||
if existing.exists():
|
if existing.exists():
|
||||||
raise forms.ValidationError(_("A user with that username already exists."))
|
raise forms.ValidationError(
|
||||||
|
_("A user with that username already exists."))
|
||||||
|
|
||||||
elif '@' in self.cleaned_data['username']:
|
elif '@' in self.cleaned_data['username']:
|
||||||
raise forms.ValidationError(_("Cannot have '@' in username."))
|
raise forms.ValidationError(_("Cannot have '@' in username."))
|
||||||
|
@ -33,8 +34,9 @@ class SniptRegistrationForm(RegistrationForm):
|
||||||
"""
|
"""
|
||||||
Validate that the supplied email address is unique for the
|
Validate that the supplied email address is unique for the
|
||||||
site.
|
site.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if User.objects.filter(email__iexact=self.cleaned_data['email']):
|
if User.objects.filter(email__iexact=self.cleaned_data['email']):
|
||||||
raise forms.ValidationError(_("This email address is already in use. Please supply a different email address."))
|
raise forms.ValidationError(
|
||||||
|
_("""This email address is already in use. Please supply a
|
||||||
|
different email address."""))
|
||||||
return self.cleaned_data['email']
|
return self.cleaned_data['email']
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
import hmac, hashlib, os
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def intercom_sha_256(user_id):
|
def intercom_sha_256(user_id):
|
||||||
return hmac.new(os.environ.get('INTERCOM_SECRET_KEY', settings.INTERCOM_SECRET_KEY), str(user_id), digestmod=hashlib.sha256).hexdigest()
|
return hmac.new(os.environ.get('INTERCOM_SECRET_KEY',
|
||||||
|
settings.INTERCOM_SECRET_KEY),
|
||||||
|
str(user_id),
|
||||||
|
digestmod=hashlib.sha256).hexdigest()
|
||||||
|
|
|
@ -20,7 +20,7 @@ class VerbatimNode(template.Node):
|
||||||
|
|
||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
return self.text
|
return self.text
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from registration.backends.default.views import RegistrationView
|
from registration.backends.default.views import RegistrationView
|
||||||
from utils.forms import SniptRegistrationForm
|
from utils.forms import SniptRegistrationForm
|
||||||
|
|
||||||
|
|
||||||
class SniptRegistrationView(RegistrationView):
|
class SniptRegistrationView(RegistrationView):
|
||||||
"""
|
"""
|
||||||
Custom registration view that uses our custom form.
|
Custom registration view that uses our custom form.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
form_class = SniptRegistrationForm
|
form_class = SniptRegistrationForm
|
||||||
|
|
34
views.py
34
views.py
|
@ -1,10 +1,9 @@
|
||||||
from accounts.models import UserProfile
|
from accounts.models import UserProfile
|
||||||
from annoying.decorators import ajax_request
|
from annoying.decorators import ajax_request, render_to
|
||||||
from blogs.views import blog_list
|
from blogs.views import blog_list
|
||||||
from django.http import HttpResponseRedirect, HttpResponseBadRequest
|
from django.http import HttpResponseRedirect, HttpResponseBadRequest
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from annoying.decorators import ajax_request, render_to
|
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from snipts.utils import get_lexers_list
|
from snipts.utils import get_lexers_list
|
||||||
|
@ -19,6 +18,7 @@ import hashlib
|
||||||
import os
|
import os
|
||||||
import stripe
|
import stripe
|
||||||
|
|
||||||
|
|
||||||
@render_to('for-teams.html')
|
@render_to('for-teams.html')
|
||||||
def for_teams(request):
|
def for_teams(request):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
|
@ -27,6 +27,7 @@ def for_teams(request):
|
||||||
profile.save()
|
profile.save()
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
@render_to('for-teams-complete.html')
|
@render_to('for-teams-complete.html')
|
||||||
def for_teams_complete(request):
|
def for_teams_complete(request):
|
||||||
|
|
||||||
|
@ -43,7 +44,8 @@ def for_teams_complete(request):
|
||||||
Info:
|
Info:
|
||||||
|
|
||||||
%s
|
%s
|
||||||
""" % (request.user.username, request.user.email, name, members, info), 'support@snipt.net',
|
""" % (request.user.username, request.user.email, name, members,
|
||||||
|
info), 'support@snipt.net',
|
||||||
['nick@nicksergeant.com'], fail_silently=False)
|
['nick@nicksergeant.com'], fail_silently=False)
|
||||||
|
|
||||||
profile = request.user.profile
|
profile = request.user.profile
|
||||||
|
@ -70,6 +72,7 @@ def for_teams_complete(request):
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
|
||||||
@render_to('homepage.html')
|
@render_to('homepage.html')
|
||||||
def homepage(request):
|
def homepage(request):
|
||||||
|
|
||||||
|
@ -99,6 +102,7 @@ def homepage(request):
|
||||||
'users_count': User.objects.all().count(),
|
'users_count': User.objects.all().count(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ajax_request
|
@ajax_request
|
||||||
def lexers(request):
|
def lexers(request):
|
||||||
lexers = get_lexers_list()
|
lexers = get_lexers_list()
|
||||||
|
@ -125,12 +129,14 @@ def lexers(request):
|
||||||
|
|
||||||
return {'objects': objects}
|
return {'objects': objects}
|
||||||
|
|
||||||
|
|
||||||
def login_redirect(request):
|
def login_redirect(request):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
return HttpResponseRedirect('/' + request.user.username + '/')
|
return HttpResponseRedirect('/' + request.user.username + '/')
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect('/')
|
return HttpResponseRedirect('/')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@render_to('pro.html')
|
@render_to('pro.html')
|
||||||
def pro(request):
|
def pro(request):
|
||||||
|
@ -138,6 +144,7 @@ def pro(request):
|
||||||
return HttpResponseRedirect('/' + request.user.username + '/')
|
return HttpResponseRedirect('/' + request.user.username + '/')
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@render_to('pro-complete.html')
|
@render_to('pro-complete.html')
|
||||||
def pro_complete(request):
|
def pro_complete(request):
|
||||||
|
@ -145,7 +152,8 @@ def pro_complete(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
|
||||||
token = request.POST['token']
|
token = request.POST['token']
|
||||||
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY', settings.STRIPE_SECRET_KEY)
|
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY',
|
||||||
|
settings.STRIPE_SECRET_KEY)
|
||||||
|
|
||||||
if 'plan' in request.GET:
|
if 'plan' in request.GET:
|
||||||
plan = request.GET['plan']
|
plan = request.GET['plan']
|
||||||
|
@ -158,7 +166,8 @@ def pro_complete(request):
|
||||||
email=request.user.email)
|
email=request.user.email)
|
||||||
except stripe.CardError, e:
|
except stripe.CardError, e:
|
||||||
error_message = e.json_body['error']['message']
|
error_message = e.json_body['error']['message']
|
||||||
return HttpResponseRedirect('/pro/?declined=%s' % error_message or 'Your card was declined.')
|
return HttpResponseRedirect('/pro/?declined=%s' % error_message or
|
||||||
|
'Your card was declined.')
|
||||||
|
|
||||||
profile = request.user.profile
|
profile = request.user.profile
|
||||||
profile.is_pro = True
|
profile.is_pro = True
|
||||||
|
@ -171,6 +180,7 @@ def pro_complete(request):
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
|
||||||
def sitemap(request):
|
def sitemap(request):
|
||||||
|
|
||||||
tags = Tag.objects.filter(snipt__public=True)
|
tags = Tag.objects.filter(snipt__public=True)
|
||||||
|
@ -182,6 +192,7 @@ def sitemap(request):
|
||||||
context_instance=RequestContext(request),
|
context_instance=RequestContext(request),
|
||||||
content_type='application/xml')
|
content_type='application/xml')
|
||||||
|
|
||||||
|
|
||||||
@render_to('tags.html')
|
@render_to('tags.html')
|
||||||
def tags(request):
|
def tags(request):
|
||||||
|
|
||||||
|
@ -198,13 +209,14 @@ def tags(request):
|
||||||
'all_tags': all_tags,
|
'all_tags': all_tags,
|
||||||
'tags': popular_tags
|
'tags': popular_tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ajax_request
|
@ajax_request
|
||||||
def user_api_key(request):
|
def user_api_key(request):
|
||||||
|
|
||||||
if not request.user.is_authenticated():
|
if not request.user.is_authenticated():
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
return {
|
|
||||||
'api_key': request.user.api_key.key
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
'api_key': request.user.api_key.key
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue