From 8d91fcde168b141ffa33173380e75739fdf45cd2 Mon Sep 17 00:00:00 2001 From: luxagraf Date: Fri, 13 Nov 2015 11:09:59 -0500 Subject: rewrote Links to make them more browse/earacble on live site and in admin, also ported to CBVs/new build system and added back some templates for viewing. Deleted tumblr integration. --- app/links/admin.py | 4 +- app/links/detail_urls.py | 10 -- app/links/models.py | 9 +- app/links/retriever.py | 34 +------ app/links/tumblr.py | 240 ----------------------------------------------- app/links/urls.py | 48 +++++++--- app/links/views.py | 33 +++++++ 7 files changed, 79 insertions(+), 299 deletions(-) delete mode 100644 app/links/detail_urls.py delete mode 100644 app/links/tumblr.py create mode 100644 app/links/views.py (limited to 'app/links') diff --git a/app/links/admin.py b/app/links/admin.py index f80e665..cbfbc52 100644 --- a/app/links/admin.py +++ b/app/links/admin.py @@ -1,11 +1,13 @@ from django.contrib import admin + +from utils.widgets import TagListFilter from links.models import Link class LinkAdmin(admin.ModelAdmin): list_display = ('title', 'admin_link', 'rating', 'pub_date', 'status') search_fields = ['title', 'description', 'url'] - list_filter = ['rating', 'status'] + list_filter = ['rating', 'status', TagListFilter] fieldsets = ( (None, { 'fields': ( diff --git a/app/links/detail_urls.py b/app/links/detail_urls.py deleted file mode 100644 index 9c76a7f..0000000 --- a/app/links/detail_urls.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.conf.urls import * -from django.views.generic.base import RedirectView -from django.views.generic.detail import DetailView -from links.models import Link - - -urlpatterns = patterns('', - (r'^$', RedirectView.as_view(url="/links/1/")), - (r'^(?P\d+)/$', DetailView.as_view(model=Link, template_name='details/link.html')), -) diff --git a/app/links/models.py b/app/links/models.py index 11a6798..cdfd786 100644 --- a/app/links/models.py +++ b/app/links/models.py @@ -1,10 +1,13 @@ import datetime +from django.core.urlresolvers import reverse from django.utils.encoding import force_text from django.db import models from django.contrib.sitemaps import Sitemap from django.contrib.syndication.views import Feed from taggit.managers import TaggableManager +import markdown + RATINGS = ( ('1', "1 Star"), ('2', "2 Stars"), @@ -36,10 +39,10 @@ class Link(models.Model): return self.title def get_absolute_url(self): - return self.url + return reverse("links:detail", kwargs={"slug": self.pk}) - def get_model_name(self): - return 'link' + def render_description(self): + return markdown.markdown(self.description, extensions=['extra'], safe_mode=False) def get_previous_published(self): return self.get_previous_by_pub_date(status__exact=1) diff --git a/app/links/retriever.py b/app/links/retriever.py index 9aec34d..843487a 100644 --- a/app/links/retriever.py +++ b/app/links/retriever.py @@ -6,19 +6,18 @@ from django.core.mail import EmailMessage from django.conf import settings from links.models import Link -# https://github.com/mgan59/python-pinboard/ -#import pinboard import requests import json + def sync_pinboard_links(): PB_URL = "https://api.pinboard.in/v1/posts/all?results=70&format=json" r = requests.get(PB_URL, auth=((settings.PIN_USER, settings.PIN_PASS))) links = json.loads(r.text) for link in links: try: - #check to see if link exists + # check to see if link exists row = Link.objects.get(link_id=link['hash']) print("already have" + row.title) except ObjectDoesNotExist: @@ -37,35 +36,6 @@ def sync_pinboard_links(): l.tags.add(t) email_link(l) -""" -def sync_pinboard_links_old(): - sync bookmarks from my pinboard account - dependancies: python-pinboard https://github.com/mgan59/python-pinboard/ - p = pinboard.open(settings.PIN_USER, settings.PIN_PASS) - dupe = False - links = p.posts(count=30) - for link in links: - try: - #check to see if link exists - row = Link.objects.get(link_id=safestr(link['hash'])) - except ObjectDoesNotExist: - l, created = Link.objects.get_or_create( - title=link['description'], - link_id=safestr(link['hash']), - url=safestr(link['href']), - description=safestr(link['extended']), - rating="3", - pub_date=datetime.datetime.strptime(link['time'], "%Y-%m-%dT%H:%M:%SZ"), - status=0 - ) - print l.title - if created: - print l.title - for t in link['tags']: - l.tags.add(t) - email_link(l) - -""" def email_link(link): """ diff --git a/app/links/tumblr.py b/app/links/tumblr.py deleted file mode 100644 index 8c0e286..0000000 --- a/app/links/tumblr.py +++ /dev/null @@ -1,240 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright 2008 Ryan Cox ( ryan.a.cox@gmail.com ) All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -'''A wrapper library for Tumblr's public web API: http://www.tumblr.com/api''' - -__author__ = 'ryan.a.cox@gmail.com' -__version__ = '0.1' - - -from urllib2 import Request, urlopen, URLError, HTTPError -from urllib import urlencode, quote -import base64 -import re - -try: - import simplejson -except ImportError: - from django.utils import simplejson - -GENERATOR = 'python-tumblr' -PAGESIZE = 50 - - -class TumblrError(Exception): - ''' General Tumblr error ''' - def __init__(self, msg): - self.msg = msg - - def __str__(self): - return self.msg - -class TumblrAuthError(TumblrError): - ''' Wraps a 403 result ''' - pass - -class TumblrRequestError(TumblrError): - ''' Wraps a 400 result ''' - pass - -class TumblrIterator: - def __init__(self, name, start, max, type): - self.name = name - self.start = start - self.max = max - self.type = type - self.results = None - self.index = 0 - - def __iter__(self): - return self - - def next(self): - if not self.results or (self.index == len(self.results['posts'])): - self.start += self.index - self.index = 0 - url = "http://%s.tumblr.com/api/read/json?start=%s&num=%s" % (self.name,self.start, PAGESIZE) - if self.type: - url += "&type=" + self.type - response = urlopen(url) - page = response.read() - m = re.match("^.*?({.*}).*$", page,re.DOTALL | re.MULTILINE | re.UNICODE) - self.results = simplejson.loads(m.group(1)) - - if (self.index >= self.max) or len(self.results['posts']) == 0: - raise StopIteration - - self.index += 1 - return self.results['posts'][self.index-1] - -class Api: - def __init__(self, name, email=None, password=None ): - self.name = name - self.is_authenticated = False - self.email = email - self.password = password - - def auth_check(self): - if self.is_authenticated: - return - url = 'http://www.tumblr.com/api/write' - values = { - 'action': 'authenticate', - 'generator' : GENERATOR, - 'email': self.email, - 'password' : self.password } - - data = urlencode(values) - req = Request(url, data) - try: - response = urlopen(req) - page = response.read() - self.url = page - self.is_authenticated = True - return - except HTTPError, e: - if 403 == e.code: - raise TumblrAuthError(str(e)) - if 400 == e.code: - raise TumblrRequestError(str(e)) - except Exception, e: - raise TumblrError(str(e)) - - - def write_regular(self, title=None, body=None, **args): - if title: - args['title'] = title - if body: - args['body'] = body - args = self._fixnames(args) - if not 'title' in args and not 'body' in args: - raise TumblrError("Must supply either body or title argument") - - self.auth_check() - args['type'] = 'regular' - return self._write(args) - - def write_photo(self, source=None, **args): - if source: - args['source'] = source - - args = self._fixnames(args) - if 'source' in args and 'data' in args: - raise TumblrError("Must NOT supply both source and data arguments") - - if not 'source' in args and not 'data' in args: - raise TumblrError("Must supply source or data argument") - - self.auth_check() - args['type'] = 'photo' - return self._write(args) - - def write_quote(self, quote=None, **args): - if quote: - args['quote'] = quote - args = self._fixnames(args) - if not 'quote' in args: - raise TumblrError("Must supply quote arguments") - - self.auth_check() - args['type'] = 'quote' - return self._write(args) - - def write_link(self, url=None, **args): - if url: - args['url'] = url - args = self._fixnames(args) - if not 'url' in args: - raise TumblrError("Must supply url argument") - - self.auth_check() - args['type'] = 'link' - return self._write(args) - - def write_conversation(self, conversation=None, **args): - if conversation: - args['conversation'] = conversation - args = self._fixnames(args) - if not 'conversation' in args: - raise TumblrError("Must supply conversation argument") - - self.auth_check() - args['type'] = 'conversation' - return self._write(args) - - def write_video(self, embed=None, **args): - if embed: - args['embed'] = embed - args = self._fixnames(args) - if 'embed' in args and 'data' in args: - raise TumblrError("Must NOT supply both embed and data arguments") - - if not 'embed' in args and not 'data' in args: - raise TumblrError("Must supply embed or data argument") - - self.auth_check() - args['type'] = 'video' - return self._write(args) - - def _fixnames(self, args): - for key in args: - if '_' in key: - value = args[key] - del args[key] - args[key.replace('_', '-')] = value - return args - - def _write(self, params, headers=None): - self.auth_check() - url = 'http://www.tumblr.com/api/write' - params['email'] = self.email - params['password'] = self.password - params['generator'] = GENERATOR - data = urlencode(params) - if headers: - req = Request(url, data, headers) - else: - req = Request(url, data) - newid = None - try: - urlopen(req) - raise TumblrError("Error writing post") - - except HTTPError, e: - if 201 == e.code: - newid = e.read() - return self.read(id=newid) - raise TumblrError(e.read()) - - def read(self, id=None, start=0,max=2**31-1,type=None): - if id: - url = "http://%s.tumblr.com/api/read/json?id=%s" % (self.name,id) - print url - response = urlopen(url) - page = response.read() - m = re.match("^.*?({.*}).*$", page,re.DOTALL | re.MULTILINE | re.UNICODE) - results = simplejson.loads(m.group(1)) - if len(results['posts']) == 0: - return None - - return results['posts'][0] - else: - return TumblrIterator(self.name,start,max,type) - -if __name__ == "__main__": - pass diff --git a/app/links/urls.py b/app/links/urls.py index fa8e042..5fdaf30 100644 --- a/app/links/urls.py +++ b/app/links/urls.py @@ -1,15 +1,37 @@ -from django.conf.urls import * -from django.views.generic import list_detail -from django.views.generic.simple import redirect_to -from links.models import Link +from django.conf.urls import url +from django.views.generic.base import RedirectView -photos_paged = { - 'queryset': Link.objects.filter(status__exact=1).order_by('-pub_date'), - 'paginate': True, - 'page_url': '/links/%d/', -} +from . import views -urlpatterns = patterns('', - (r'^(?P\d+)/$', list_detail.object_list, dict(photos_paged, template_name='archives/links.html')), - (r'^$', redirect_to, {'url': '/links/1/'}), -) +urlpatterns = [ + url( + regex=r'tag/(?P[-\w]+)/(?P\d+)/$', + view=views.LinkTagListView.as_view(), + name='list-tag' + ), + url( + regex=r'(?P[-\d]+).txt$', + view=views.LinkDetailViewTXT.as_view(), + name="detail-txt" + ), + url( + regex=r'(?P[-\d]+)$', + view=views.LinkDetailView.as_view(), + name='detail' + ), + url( + regex=r'(?P\d+)/$', + view=views.LinkListView.as_view(), + name='list' + ), + url( + regex=r'^tag/(?P[-\w]+)/$', + view=RedirectView.as_view(url="/links/tag/%(slug)s/1/", permanent=False), + name="live-redirect-tag" + ), + url( + regex=r'^$', + view=RedirectView.as_view(url="/links/1/", permanent=False), + name="live-redirect" + ), +] diff --git a/app/links/views.py b/app/links/views.py new file mode 100644 index 0000000..36ccca3 --- /dev/null +++ b/app/links/views.py @@ -0,0 +1,33 @@ +from django.views.generic.detail import DetailView +from utils.views import PaginatedListView + +from .models import Link +from taggit.models import Tag + + +class LinkListView(PaginatedListView): + model = Link + template_name = 'archives/links.html' + + +class LinkTagListView(PaginatedListView): + model = Link + template_name = 'archives/links.html' + + def get_queryset(self): + return Link.objects.filter(tags__name=self.kwargs['slug']) + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = super(LinkTagListView, self).get_context_data(**kwargs) + context['tag'] = Tag.objects.get(slug__exact=self.kwargs['slug']) + return context + +class LinkDetailView(DetailView): + model = Link + template_name = "details/link.html" + slug_field = "id" + + +class LinkDetailViewTXT(LinkDetailView): + template_name = "details/entry.txt" -- cgit v1.2.3-70-g09d2