snipt/snipts/api.py

566 lines
18 KiB
Python
Raw Normal View History

2015-07-24 18:28:31 -07:00
import datetime
import hashlib
2015-07-24 18:39:25 -07:00
import parsedatetime as pdt
2015-07-24 18:28:31 -07:00
import re
2016-05-09 09:35:49 -07:00
import requests
2015-07-24 18:28:31 -07:00
import time
2012-05-27 11:51:21 -07:00
2015-07-24 18:39:25 -07:00
from accounts.models import UserProfile
2016-05-09 09:35:49 -07:00
from django.conf import settings
2015-07-24 18:39:25 -07:00
from django.contrib.auth.models import User
from django.db import models
from django.template.defaultfilters import date, urlize, linebreaksbr
from haystack.query import SearchQuerySet
from snipts.models import Favorite, Snipt
from taggit.models import Tag
from taggit.utils import edit_string_for_tags, parse_tags
from tastypie import fields
from tastypie.authentication import ApiKeyAuthentication
from tastypie.authorization import Authorization
from tastypie.cache import SimpleCache
from tastypie.exceptions import Unauthorized
from tastypie.fields import ListField
from tastypie.models import create_api_key
from tastypie.resources import ModelResource
from tastypie.validation import Validation
2012-04-13 10:13:19 -07:00
2012-01-29 17:48:17 -08:00
models.signals.post_save.connect(create_api_key, sender=User)
2011-10-01 10:23:05 -07:00
2011-10-02 15:38:20 -07:00
class PrivateFavoriteAuthorization(Authorization):
def read_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user)
def read_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
raise Unauthorized()
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
2015-07-24 18:28:31 -07:00
class PrivateSniptAuthorization(Authorization):
def read_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user)
def read_detail(self, object_list, bundle):
return bundle.obj.is_authorized_user(bundle.request.user)
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
user = bundle.obj.user
if user == bundle.request.user:
return True
if user.profile.is_a_team:
return user.team.user_is_member(bundle.request.user)
return False
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
return bundle.obj.is_authorized_user(bundle.request.user)
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
2015-10-18 12:19:46 -07:00
return bundle.obj.is_authorized_user(bundle.request.user)
2015-07-24 18:28:31 -07:00
class PrivateUserProfileAuthorization(Authorization):
def read_list(self, object_list, bundle):
raise Unauthorized()
def read_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
raise Unauthorized()
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
raise Unauthorized()
2015-07-24 18:28:31 -07:00
class PrivateUserAuthorization(Authorization):
def read_list(self, object_list, bundle):
raise Unauthorized()
def read_detail(self, object_list, bundle):
return bundle.obj == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
raise Unauthorized()
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
raise Unauthorized()
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
raise Unauthorized()
2012-04-12 19:04:37 -07:00
class FavoriteValidation(Validation):
def is_valid(self, bundle, request=None):
2012-04-12 19:04:37 -07:00
errors = {}
2019-01-23 15:52:55 -08:00
snipt = bundle.data["snipt"]
2012-04-12 19:04:37 -07:00
2019-01-23 15:52:55 -08:00
if Favorite.objects.filter(user=bundle.request.user, snipt=snipt).count():
errors = "User has already favorited this snipt."
2012-04-12 19:04:37 -07:00
return errors
2015-07-24 18:28:31 -07:00
2014-05-04 19:47:15 -07:00
class SniptValidation(Validation):
def is_valid(self, bundle, request=None):
errors = {}
2019-01-23 15:52:55 -08:00
if len(bundle.data["title"]) > 255:
errors = "Title must be 255 characters or less."
2016-05-09 09:35:49 -07:00
2014-05-04 19:47:15 -07:00
return errors
2015-07-24 18:28:31 -07:00
class UserProfileValidation(Validation):
def is_valid(self, bundle, request=None):
errors = {}
for field in bundle.data:
if bundle.data[field]:
2019-01-23 15:52:55 -08:00
if not re.match("^[ A-Za-z0-9\/\@\._-]*$", bundle.data[field]):
errors[field] = (
"Only spaces, letters, numbers, "
"underscores, dashes, periods, forward "
'slashes, and "at sign" are valid.'
)
return errors
2012-04-12 19:04:37 -07:00
2011-10-01 16:09:59 -07:00
class PublicUserResource(ModelResource):
class Meta:
2011-10-02 13:07:47 -07:00
queryset = User.objects.all()
2019-01-23 15:52:55 -08:00
resource_name = "user"
fields = ["id", "username"]
2011-10-02 13:16:58 -07:00
include_absolute_url = True
2019-01-23 15:52:55 -08:00
allowed_methods = ["get"]
filtering = {"username": ["contains", "exact"]}
2012-08-27 09:01:37 -07:00
max_limit = 200
2011-10-02 15:57:41 -07:00
cache = SimpleCache()
2011-10-01 16:09:59 -07:00
2011-10-03 17:42:00 -07:00
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["snipts"] = "/api/public/snipt/?user=%d" % bundle.obj.id
bundle.data["email_md5"] = hashlib.md5(
bundle.obj.email.lower().encode("utf-8")
).hexdigest()
bundle.data["snipts_count"] = Snipt.objects.filter(
user=bundle.obj.id, public=True
).count()
2011-10-03 17:42:00 -07:00
return bundle
2011-10-01 16:09:59 -07:00
2015-07-24 18:28:31 -07:00
2014-05-26 14:28:13 -07:00
class PublicTagResource(ModelResource):
class Meta:
queryset = Tag.objects.filter()
2019-01-23 15:52:55 -08:00
queryset = queryset.annotate(count=models.Count("taggit_taggeditem_items__id"))
queryset = queryset.order_by("-count", "name")
resource_name = "tag"
fields = ["id", "name"]
allowed_methods = ["get"]
2014-05-26 14:28:13 -07:00
max_limit = 200
cache = SimpleCache()
2016-11-01 09:59:35 -07:00
def build_filters(self, filters=None, **kwargs):
2014-05-26 14:28:13 -07:00
if filters is None:
filters = {}
2014-05-26 14:28:13 -07:00
orm_filters = super(PublicTagResource, self).build_filters(filters)
2019-01-23 15:52:55 -08:00
if "q" in filters:
orm_filters["slug"] = filters["q"]
2014-05-26 14:28:13 -07:00
return orm_filters
2014-05-26 14:28:13 -07:00
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["absolute_url"] = "/public/tag/%s/" % bundle.obj.slug
bundle.data["snipts"] = "/api/public/snipt/?tag=%d" % bundle.obj.id
2014-05-26 14:28:13 -07:00
return bundle
2011-10-01 16:09:59 -07:00
2015-07-24 18:28:31 -07:00
2011-10-01 16:09:59 -07:00
class PublicSniptResource(ModelResource):
2019-01-23 15:52:55 -08:00
user = fields.ForeignKey(PublicUserResource, "user", full=True)
tags = fields.ToManyField(PublicTagResource, "tags", related_name="tag", full=True)
2011-10-01 10:23:05 -07:00
class Meta:
2019-01-23 15:52:55 -08:00
queryset = Snipt.objects.filter(public=True).order_by("-created")
resource_name = "snipt"
fields = [
"id",
"title",
"slug",
"lexer",
"code",
"description",
"line_count",
"stylized",
"created",
"modified",
"publish_date",
"blog_post",
"meta",
]
2011-10-02 13:16:58 -07:00
include_absolute_url = True
2019-01-23 15:52:55 -08:00
allowed_methods = ["get"]
filtering = {"user": "exact", "blog_post": "exact"}
ordering = ["created", "modified"]
2015-09-15 08:57:57 -07:00
max_limit = 200
2011-10-02 15:57:41 -07:00
cache = SimpleCache()
2011-10-01 16:09:59 -07:00
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["embed_url"] = bundle.obj.get_embed_url()
bundle.data["raw_url"] = bundle.obj.get_raw_url()
bundle.data["full_absolute_url"] = bundle.obj.get_full_absolute_url()
bundle.data["description_rendered"] = linebreaksbr(
urlize(bundle.obj.description)
)
log_entries = bundle.obj.sniptlogentry_set.all()
bundle_log_entries = []
for entry in log_entries:
2019-01-23 15:52:55 -08:00
bundle_log_entries.append(
{
"created": entry.created,
"user": entry.user,
"code": entry.code,
"diff": entry.diff,
}
)
2019-01-23 15:52:55 -08:00
bundle.data["log_entries"] = bundle_log_entries
2019-01-23 15:52:55 -08:00
if "omit_code" in bundle.request.GET:
del bundle.data["code"]
2019-01-23 15:52:55 -08:00
if "omit_stylized" in bundle.request.GET:
del bundle.data["stylized"]
2015-04-03 09:27:02 -07:00
2011-10-01 16:09:59 -07:00
return bundle
2011-10-02 15:38:20 -07:00
2016-11-01 09:59:35 -07:00
def build_filters(self, filters=None, **kwargs):
2011-10-02 15:38:20 -07:00
if filters is None:
filters = {}
orm_filters = super(PublicSniptResource, self).build_filters(filters)
2019-01-23 15:52:55 -08:00
if "tag" in filters:
tag = Tag.objects.get(pk=filters["tag"])
2011-10-02 15:38:20 -07:00
tagged_items = tag.taggit_taggeditem_items.all()
2019-01-23 15:52:55 -08:00
orm_filters["pk__in"] = [i.object_id for i in tagged_items]
2011-10-02 15:38:20 -07:00
2019-01-23 15:52:55 -08:00
if "q" in filters:
sqs = SearchQuerySet().auto_query(filters["q"])
orm_filters["pk__in"] = [i.pk for i in sqs]
2012-05-09 14:18:09 -07:00
2011-10-02 15:38:20 -07:00
return orm_filters
2011-12-22 20:36:06 -08:00
class PrivateUserProfileResource(ModelResource):
class Meta:
queryset = UserProfile.objects.all()
2019-01-23 15:52:55 -08:00
resource_name = "profile"
excludes = ["is_pro"]
validation = UserProfileValidation()
include_absolute_url = False
2019-01-23 15:52:55 -08:00
allowed_methods = ["get", "put"]
list_allowed_methods = []
authentication = ApiKeyAuthentication()
authorization = PrivateUserProfileAuthorization()
always_return_data = True
max_limit = 200
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["email"] = bundle.obj.user.email
bundle.data["username"] = bundle.obj.user.username
bundle.data["user_id"] = bundle.obj.user.id
bundle.data["api_key"] = bundle.obj.user.api_key.key
return bundle
2015-07-24 18:28:31 -07:00
2011-12-25 13:00:41 -08:00
class PrivateUserResource(ModelResource):
2019-01-23 15:52:55 -08:00
profile = fields.ForeignKey(PrivateUserProfileResource, "profile", full=False)
2011-12-25 13:00:41 -08:00
class Meta:
queryset = User.objects.all()
2019-01-23 15:52:55 -08:00
resource_name = "user"
fields = ["id", "username", "email"]
2011-12-25 13:00:41 -08:00
include_absolute_url = True
2019-01-23 15:52:55 -08:00
allowed_methods = ["get"]
2011-12-25 13:00:41 -08:00
list_allowed_methods = []
2012-01-29 17:48:17 -08:00
authentication = ApiKeyAuthentication()
authorization = PrivateUserAuthorization()
always_return_data = True
2012-08-27 09:01:37 -07:00
max_limit = 200
2011-12-25 13:00:41 -08:00
cache = SimpleCache()
2012-04-13 10:13:19 -07:00
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["email_md5"] = hashlib.md5(
bundle.obj.email.lower().encode("utf-8")
).hexdigest()
bundle.data["stats"] = {
"public_snipts": Snipt.objects.filter(
user=bundle.obj.id, public=True
).count(),
"private_snipts": Snipt.objects.filter(
user=bundle.obj.id, public=False
).count(),
"total_snipts": Snipt.objects.filter(user=bundle.obj.id).count(),
"total_views": Snipt.objects.filter(user=bundle.obj.id).aggregate(
models.Sum("views")
)["views__sum"],
2015-01-03 08:08:47 -08:00
}
user_snipts = Snipt.objects.filter(user=bundle.obj)
2019-01-23 15:52:55 -08:00
user_tags = [snipt["tags"] for snipt in user_snipts.values("tags").distinct()]
tags = [
2019-01-23 15:52:55 -08:00
tag["name"]
for tag in Tag.objects.filter(id__in=user_tags).values("name").distinct()
]
2019-01-23 15:52:55 -08:00
bundle.data["tags"] = tags
2019-01-23 15:52:55 -08:00
bundle.data["lexers"] = [
snipt["lexer"] for snipt in user_snipts.values("lexer").distinct()
]
2012-04-13 10:13:19 -07:00
return bundle
2015-07-24 18:28:31 -07:00
2011-12-22 20:36:06 -08:00
class PrivateSniptResource(ModelResource):
2019-01-23 15:52:55 -08:00
user = fields.ForeignKey(PrivateUserResource, "user", full=True)
last_user_saved = fields.ForeignKey(
PrivateUserResource, "last_user_saved", null=True, full=False
)
2012-01-29 20:49:14 -08:00
tags_list = ListField()
2019-01-23 15:52:55 -08:00
tags = fields.ToManyField(PublicTagResource, "tags", related_name="tag", full=True)
2011-12-25 13:00:41 -08:00
2011-12-22 20:36:06 -08:00
class Meta:
2019-01-23 15:52:55 -08:00
queryset = Snipt.objects.all().order_by("-created")
resource_name = "snipt"
fields = [
"id",
"title",
"slug",
"lexer",
"code",
"description",
"line_count",
"stylized",
"key",
"public",
"secure",
"blog_post",
"created",
"modified",
"publish_date",
"meta",
]
2011-12-22 20:36:06 -08:00
include_absolute_url = True
2019-01-23 15:52:55 -08:00
detail_allowed_methods = ["get", "patch", "put", "delete"]
list_allowed_methods = ["get", "post"]
2012-01-29 17:48:17 -08:00
authentication = ApiKeyAuthentication()
authorization = PrivateSniptAuthorization()
2014-05-04 19:47:15 -07:00
validation = SniptValidation()
2019-01-23 15:52:55 -08:00
ordering = ["created", "modified"]
always_return_data = True
2015-09-15 08:57:57 -07:00
max_limit = 200
2012-01-29 19:04:52 -08:00
cache = SimpleCache()
2011-12-22 20:36:06 -08:00
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["embed_url"] = bundle.obj.get_embed_url()
bundle.data["raw_url"] = bundle.obj.get_raw_url()
bundle.data["tags_list"] = edit_string_for_tags(bundle.obj.tags.all())
bundle.data["full_absolute_url"] = bundle.obj.get_full_absolute_url()
bundle.data["description_rendered"] = linebreaksbr(
urlize(bundle.obj.description)
)
bundle.data["views"] = bundle.obj.views
bundle.data["favs"] = bundle.obj.favs()
if bundle.data["publish_date"]:
bundle.data["publish_date"] = date(
bundle.data["publish_date"], "M d, Y \\a\\t h:i A"
)
2012-05-27 11:51:21 -07:00
log_entries = bundle.obj.sniptlogentry_set.all()
bundle_log_entries = []
for entry in log_entries:
2019-01-23 15:52:55 -08:00
bundle_log_entries.append(
{
"created": entry.created,
"user": entry.user,
"code": entry.code,
"diff": entry.diff,
}
)
2019-01-23 15:52:55 -08:00
bundle.data["log_entries"] = bundle_log_entries
2011-12-22 20:36:06 -08:00
return bundle
2013-03-24 15:41:57 -07:00
def obj_create(self, bundle, **kwargs):
2019-01-23 15:52:55 -08:00
bundle.data["last_user_saved"] = bundle.request.user
bundle.data["tags_list"] = bundle.data.get("tags")
bundle.data["tags"] = []
if "intended_user" in bundle.data:
bundle.data["user"] = User.objects.get(
username=bundle.data["intended_user"]
)
2015-11-10 08:03:48 -08:00
else:
2019-01-23 15:52:55 -08:00
bundle.data["user"] = bundle.request.user
2012-05-24 19:20:06 -07:00
2019-01-23 15:52:55 -08:00
if "blog_post" in bundle.data:
2012-05-29 07:49:42 -07:00
bundle = self._clean_publish_date(bundle)
2012-05-27 11:51:21 -07:00
2019-01-23 15:52:55 -08:00
return super(PrivateSniptResource, self).obj_create(bundle, **kwargs)
2011-12-22 20:36:06 -08:00
2013-03-24 15:41:57 -07:00
def obj_update(self, bundle, **kwargs):
2019-01-23 15:52:55 -08:00
instance = Snipt.objects.get(pk=bundle.data["id"])
2019-01-23 15:52:55 -08:00
if instance.user.profile.is_a_team:
user = instance.user
else:
user = bundle.request.user
2019-01-23 15:52:55 -08:00
bundle.data["created"] = None
bundle.data["last_user_saved"] = bundle.request.user
bundle.data["modified"] = None
bundle.data["user"] = user
2012-07-08 20:55:18 -07:00
2019-01-23 15:52:55 -08:00
if type(bundle.data["tags"]) == str or type(bundle.data["tags"]) == unicode:
bundle.data["tags_list"] = bundle.data["tags"]
2012-01-30 19:20:31 -08:00
else:
2019-01-23 15:52:55 -08:00
bundle.data["tags_list"] = ""
bundle.data["tags"] = ""
2012-05-24 19:20:06 -07:00
2019-01-23 15:52:55 -08:00
if "blog_post" in bundle.data:
2012-05-29 07:49:42 -07:00
bundle = self._clean_publish_date(bundle)
2012-05-27 11:51:21 -07:00
2019-01-23 15:52:55 -08:00
return super(PrivateSniptResource, self).obj_update(bundle, **kwargs)
2012-01-30 19:20:31 -08:00
2012-05-27 11:51:21 -07:00
def _clean_publish_date(self, bundle):
2019-01-23 15:52:55 -08:00
if bundle.data["blog_post"] and "publish_date" not in bundle.data:
bundle.data["publish_date"] = datetime.datetime.now()
elif bundle.data["publish_date"] == "":
bundle.data["publish_date"] = datetime.datetime.now()
elif bundle.data["blog_post"]:
2013-03-15 11:35:31 -07:00
c = pdt.Constants()
2012-05-27 11:51:21 -07:00
p = pdt.Calendar(c)
2019-01-23 15:52:55 -08:00
publish_date, result = p.parse(bundle.data["publish_date"])
2012-05-27 11:51:21 -07:00
if result != 0:
2019-01-23 15:52:55 -08:00
publish_date = time.strftime("%Y-%m-%d %H:%M:%S", publish_date)
2012-05-27 11:51:21 -07:00
else:
publish_date = datetime.datetime.now()
2019-01-23 15:52:55 -08:00
bundle.data["publish_date"] = publish_date
elif not bundle.data["blog_post"]:
bundle.data["publish_date"] = None
2012-05-27 11:51:21 -07:00
return bundle
2016-11-01 09:59:35 -07:00
def build_filters(self, filters=None, **kwargs):
2011-12-25 13:00:41 -08:00
if filters is None:
filters = {}
orm_filters = super(PrivateSniptResource, self).build_filters(filters)
2019-01-23 15:52:55 -08:00
if "tag" in filters:
tag = Tag.objects.get(pk=filters["tag"])
2011-12-25 13:00:41 -08:00
tagged_items = tag.taggit_taggeditem_items.all()
2019-01-23 15:52:55 -08:00
orm_filters["pk__in"] = [i.object_id for i in tagged_items]
2011-12-25 13:00:41 -08:00
2019-01-23 15:52:55 -08:00
if "q" in filters:
user = User.objects.get(username=filters["username"])
sqs = SearchQuerySet().filter(author=user, content=filters["q"])
orm_filters["pk__in"] = [i.pk for i in sqs]
2012-05-09 14:18:09 -07:00
2011-12-25 13:00:41 -08:00
return orm_filters
2012-01-29 20:49:14 -08:00
def save_m2m(self, bundle):
2019-01-23 15:52:55 -08:00
tags = bundle.data.get("tags_list", [])
if tags != "":
2012-01-30 19:20:31 -08:00
bundle.obj.tags.set(*parse_tags(tags))
2012-07-08 20:55:18 -07:00
else:
bundle.obj.tags.set()
2012-07-04 08:03:09 -07:00
2015-07-24 18:28:31 -07:00
2012-04-12 19:04:37 -07:00
class PrivateFavoriteResource(ModelResource):
2019-01-23 15:52:55 -08:00
user = fields.ForeignKey(PrivateUserResource, "user", full=True)
snipt = fields.ForeignKey(PrivateSniptResource, "snipt", full=False)
2012-04-12 19:04:37 -07:00
class Meta:
2019-01-23 15:52:55 -08:00
queryset = Favorite.objects.all().order_by("-created")
resource_name = "favorite"
fields = ["id"]
2012-04-12 19:04:37 -07:00
validation = FavoriteValidation()
2019-01-23 15:52:55 -08:00
detail_allowed_methods = ["get", "post", "delete"]
list_allowed_methods = ["get", "post"]
2012-04-12 19:04:37 -07:00
authentication = ApiKeyAuthentication()
authorization = PrivateFavoriteAuthorization()
2019-01-23 15:52:55 -08:00
ordering = ["created"]
2012-04-12 19:04:37 -07:00
always_return_data = True
2012-08-27 09:01:37 -07:00
max_limit = 200
2012-04-12 19:04:37 -07:00
cache = SimpleCache()
def dehydrate(self, bundle):
2019-01-23 15:52:55 -08:00
bundle.data["snipt"] = "/api/public/snipt/{}/".format(bundle.obj.snipt.pk)
return bundle
2013-03-24 15:41:57 -07:00
def obj_create(self, bundle, **kwargs):
2019-01-23 15:52:55 -08:00
bundle.data["user"] = bundle.request.user
bundle.data["snipt"] = Snipt.objects.get(pk=bundle.data["snipt"])
return super(PrivateFavoriteResource, self).obj_create(
bundle, user=bundle.request.user, **kwargs
)