# gLifestream Copyright (C) 2009, 2010, 2011, 2013 Wojciech Polak
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see .
import time
import datetime
from urlparse import urljoin
from django.conf import settings
from django.core import urlresolvers
from django.http import HttpResponse
from django.http import HttpResponseForbidden
from django.http import HttpResponseRedirect
from django.http import HttpResponseNotFound
from django.http import HttpResponsePermanentRedirect
from django.http import Http404
from django.shortcuts import render_to_response
from django.template.loader import render_to_string
from django.template.defaultfilters import fix_ampersands
from django.template.defaultfilters import truncatewords
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
from django.utils.html import escape, strip_spaces_between_tags
from django.views.decorators.cache import never_cache
from glifestream.stream.templatetags.gls_filters import gls_content
from glifestream.stream.templatetags.gls_filters import gls_slugify
from glifestream.stream.models import Service, Entry, Favorite, List
from glifestream.stream import media, pshb
from glifestream.utils import common
from glifestream.utils.time import pn_month_start
from glifestream.apis import API_LIST, selfposts
try:
import json
except ImportError:
import simplejson as json
def index(request, **args):
site_url = '%s://%s' % (request.is_secure() and 'https' or 'http',
request.get_host())
page = {
'ctx': args.get('ctx', ''),
'backtime': True,
'robots': 'index',
'public': False,
'site_url': site_url,
'base_url': settings.BASE_URL,
'login_url': settings.LOGIN_URL,
'favicon': settings.FAVICON,
'author_name': settings.FEED_AUTHOR_NAME,
'author_uri': getattr(settings, 'FEED_AUTHOR_URI', False),
'taguri': settings.FEED_TAGURI,
'icon': settings.FEED_ICON,
'maps_engine': settings.MAPS_ENGINE,
'fb_app_id': settings.FACEBOOK_APP_ID,
'pshb_hubs': settings.PSHB_HUBS,
}
authed = request.user.is_authenticated() and request.user.is_staff
friend = request.user.is_authenticated() and not request.user.is_staff
urlparams = []
entries_on_page = settings.ENTRIES_ON_PAGE
entries_orderby = 'date_published'
# Entries filter.
fs = {'active': True, 'service__home': True}
# Filter by dates.
year = int(args.get('year', 0))
month = int(args.get('month', 0))
day = int(args.get('day', 0))
if year:
fs[entries_orderby + '__year'] = year
if month:
fs[entries_orderby + '__month'] = month
if day:
fs[entries_orderby + '__day'] = day
if year and month and day:
dt = datetime.date(year, month, day).strftime('%Y/%m/%d')
elif year and month:
dt = datetime.date(year, month, 1)
prev, next = pn_month_start(dt)
page['month_nav'] = True
page['month_prev'] = prev.strftime('%Y/%m')
page['month_next'] = next.strftime('%Y/%m')
dt = dt.strftime('%Y/%m')
elif year:
dt = datetime.date(year, 1, 1).strftime('%Y')
if year:
page['backtime'] = False
page['title'] = dt
page['subtitle'] = _(
'You are currently browsing the archive for %s') % (''+dt+'')
page['robots'] = 'noindex'
if page['backtime']:
entries = Entry.objects.order_by('-' + entries_orderby)
else:
entries = Entry.objects.order_by(entries_orderby)
if not authed:
fs['draft'] = False
if not authed or page['ctx'] == 'public':
fs['service__public'] = True
page['public'] = True
# Filter for favorites.
if page['ctx'] == 'favorites':
if not authed:
return HttpResponseRedirect(settings.BASE_URL + '/')
favs = Favorite.objects.filter(user__id=request.user.id)
page['favorites'] = True
page['title'] = _('Favorites')
page['subtitle'] = _(
'You are currently browsing your favorite entries')
fs['id__in'] = favs.values('entry')
# Filter lists.
elif 'list' in args:
try:
services = List.objects.get(user__id=request.user.id,
slug=args['list']).services
del fs['service__home']
fs['service__id__in'] = services.values('id')
page['ctx'] = 'list/' + args['list']
page['title'] = args['list']
page['subtitle'] = _('You are currently browsing entries from %s list only.') % (
'' + args['list'] + '')
except List.DoesNotExist:
if authed:
raise Http404
# Filter for exactly one given entry.
elif 'entry' in args:
fs['id__exact'] = int(args['entry'])
page['exactentry'] = True
if authed and 'service__public' in fs:
del fs['service__public']
if not authed:
page['ctx'] = ''
# Filter by class type.
cls = request.GET.get('class', 'all')
if cls != 'all':
fs['service__cls'] = cls
urlparams.append('class=' + cls)
page['robots'] = 'noindex'
if 'subtitle' in page:
page['subtitle'] += ' (%s)' % escape(cls.capitalize())
else:
page['subtitle'] = _('You are currently browsing %s entries only.') % (
'' + escape(cls) + '')
# Filter by author name.
author = request.GET.get('author', 'all')
if author != 'all':
fs['author_name'] = author
urlparams.append('author=' + author)
page['robots'] = 'noindex'
# Filter by service type.
srvapi = request.GET.get('service', 'all')
if srvapi != 'all':
fs['service__api'] = srvapi
urlparams.append('service=' + srvapi)
page['robots'] = 'noindex'
srvapi_name = dict(API_LIST).get(srvapi, srvapi.capitalize())
if 'subtitle' in page:
page['subtitle'] += ' (%s)' % escape(srvapi_name)
else:
page['subtitle'] = _('You are currently browsing entries from %s service only.') % (
'' + escape(srvapi_name) + '')
# Filter entries after specified timestamp 'start'.
after = False
start = request.GET.get('start', False)
if start:
qs = fs.copy()
try:
dt = datetime.datetime.fromtimestamp(float(start))
except ValueError:
raise Http404
if page['backtime']:
fs[entries_orderby + '__lte'] = dt
qs[entries_orderby + '__gt'] = fs[entries_orderby + '__lte']
q = Entry.objects.order_by(entries_orderby)
else:
fs[entries_orderby + '__gte'] = dt
qs[entries_orderby + '__lt'] = fs[entries_orderby + '__gte']
q = Entry.objects.order_by('-' + entries_orderby)
q = q.filter(**qs)[0:entries_on_page].values(entries_orderby)
if len(q):
after = q[len(q) - 1][entries_orderby]
after = int(time.mktime(after.timetuple()))
page['title'] = '%s' % str(dt)[0:-3]
page['robots'] = 'noindex'
# Search/Query entries.
search_enable = getattr(settings, 'SEARCH_ENABLE', False)
search_engine = getattr(settings, 'SEARCH_ENGINE', 'sphinx')
search_query = request.GET.get('s', '')
if search_query != '' and search_enable:
page['search'] = search_query
page['title'] = 'Search Results for %s' % escape(search_query)
page['subtitle'] = _('Your search for %s returned the following results.') % (
'' + escape(search_query) + '')
urlparams.append('s=' + search_query)
sfs = {}
if not authed and not friend:
sfs['friends_only'] = False
page_number = int(request.GET.get('page', 1))
offset = (page_number - 1) * entries_on_page
try:
if search_engine == 'sphinx' and Entry.sphinx.query:
if page['public']:
sfs['public'] = True
entries = Entry.sphinx.query(
search_query).filter(**sfs).select_related()
else:
if page['public']:
sfs['service__public'] = True
sfs['content__icontains'] = search_query
entries = entries.filter(**sfs).select_related()
limit = offset + entries_on_page
if offset >= entries_on_page:
page['prevpage'] = page_number - 1
if limit < entries.count():
page['nextpage'] = page_number + 1
entries = entries[offset:limit]
except:
entries = []
start = False
# If not search, then normal query.
else:
entries = entries.filter(**fs)[0:entries_on_page + 1].select_related()
num = len(entries)
if 'exactentry' in page and num:
page['title'] = truncatewords(entries[0].title, 7)
# Time-based pagination.
if num > entries_on_page:
start = entries[num - 1].__getattribute__(entries_orderby)
start = int(time.mktime(start.timetuple()))
else:
start = False
entries = entries[0:entries_on_page]
if num:
crymax = entries[0].date_published.year
crymin = entries[len(entries) - 1].date_published.year
if crymin != crymax:
page['copyright_years'] = '%s-%s' % (crymin, crymax)
else:
page['copyright_years'] = crymin
# Build URL params for links.
if len(urlparams):
urlparams = '?' + reduce(lambda x, y: unicode(x) + '&' + unicode(y),
urlparams, '')[1:] + '&'
else:
urlparams = '?'
if len(entries):
page['updated'] = entries[0].date_published
else:
page['updated'] = datetime.datetime.utcnow()
page['urlparams'] = urlparams
page['start'] = start
page['after'] = after
if hasattr(settings, 'STREAM_TITLE'):
page_title = settings.STREAM_TITLE
else:
page_title = None
if hasattr(settings, 'STREAM_DESCRIPTION'):
page['description'] = settings.STREAM_DESCRIPTION
# Set page theme.
page['themes'] = settings.THEMES
page['themes_more'] = True if len(settings.THEMES) > 1 else False
page['theme'] = common.get_theme(request)
# Setup links.
page['need_fbc'] = False
for entry in entries:
entry.only_for_friends = entry.friends_only
if authed or friend:
entry.friends_only = False
elif entry.friends_only:
page['need_fbc'] = True
if not entry.friends_only:
entry.gls_link = '%s/%s' % (urlresolvers.reverse('entry', args=[entry.id]),
gls_slugify(truncatewords(entry.title, 7)))
else:
entry.gls_link = '%s/' % (
urlresolvers.reverse('entry', args=[entry.id]))
if 'title' in page:
del page['title']
entry.gls_absolute_link = '%s%s' % (page['site_url'], entry.gls_link)
# Check single-entry URL
if 'exactentry' in page:
if len(entries):
gls_link = entries[0].gls_link
if gls_link != request.path:
return HttpResponsePermanentRedirect(gls_link)
page['canonical_link'] = urljoin(settings.BASE_URL, gls_link)
else:
raise Http404
if 'title' in page and page['title'] != '':
if page_title:
page['title'] += getattr(settings, 'STREAM_TITLE_SUFFIX',
' | ' + page_title)
elif page_title:
page['title'] = page_title
# Pickup right output format and finish.
format = request.GET.get('format', 'html')
if format == 'atom':
return render_to_response('stream.atom',
{'entries': entries,
'page': page},
mimetype='application/atom+xml')
elif format == 'json':
cb = request.GET.get('callback', False)
return render_to_response('stream.json',
{'entries': entries,
'page': page,
'callback': cb},
mimetype='application/json')
elif format == 'html-pure' and request.is_ajax():
# Check which entry is already favorite.
if authed and page['ctx'] != 'favorites':
ents = [entry.id for entry in entries]
favs = Favorite.objects.filter(user__id=request.user.id,
entry__id__in=ents)
favs = [f.entry_id for f in favs]
for entry in entries:
if entry.id in favs:
entry.fav = True
if entry.service.api in ('twitter', 'identica'):
entry.sms = True
d = {
'next': page['start'],
'stream': strip_spaces_between_tags(
render_to_string('stream-pure.html',
{'entries': entries,
'page': page,
'authed': authed,
'friend': friend})),
}
if 'nextpage' in page:
d['next'] = page['nextpage']
return HttpResponse(json.dumps(d), mimetype='application/json')
elif format != 'html':
raise Http404
else:
# Check which entry is already favorite.
if authed and page['ctx'] != 'favorites':
ents = [entry.id for entry in entries]
favs = Favorite.objects.filter(user__id=request.user.id,
entry__id__in=ents)
favs = [f.entry_id for f in favs]
for entry in entries:
if entry.id in favs:
entry.fav = True
if entry.service.api in ('twitter', 'identica'):
entry.sms = True
# Get lists.
lists = List.objects.filter(
user__id=request.user.id).order_by('name')
# Get archives.
if 'entry' in args:
qs = {}
else:
qs = fs.copy()
if year:
del qs[entries_orderby + '__year']
if month:
del qs[entries_orderby + '__month']
if day:
del qs[entries_orderby + '__day']
archs = Entry.objects.filter(**qs).dates('date_published',
'month', order='DESC')
page['months12'] = [datetime.date(2010, x, 1) for x in range(1, 13)]
# List available classes.
fs = {}
if not authed or page['ctx'] == 'public':
fs['public'] = True
_classes = Service.objects.filter (**fs).order_by ('id')\
.values('api', 'cls')
classes = {}
for item in _classes:
if item['cls'] not in classes:
classes[item['cls']] = item
classes = classes.values()
accept_lang = request.META.get('HTTP_ACCEPT_LANGUAGE', '').split(',')
for i, lang in enumerate(accept_lang):
accept_lang[i] = lang.split(';')[0]
page['lang'] = accept_lang[0]
request.user.fb_username = request.session.get('fb_username', '')
request.user.fb_profile_url = request.session.get(
'fb_profile_url', '')
res = render_to_response('stream.html',
{'classes': classes,
'entries': entries,
'lists': lists,
'archives': archs,
'page': page,
'authed': authed,
'friend': friend,
'has_search': search_enable,
'is_secure': request.is_secure(),
'user': request.user})
res['X-XRDS-Location'] = request.build_absolute_uri(
urlresolvers.reverse('glifestream.gauth.views.xrds'))
return res
@never_cache
def pshb_dispatcher(request, **args):
if request.method == 'GET':
res = pshb.verify(args['id'], request.GET)
if res:
return HttpResponse(res)
elif request.method == 'POST':
pshb.accept_payload(args['id'], request.raw_post_data, request.META)
return HttpResponse()
raise Http404
def page_not_found(request, **args):
from django.template import RequestContext, loader
page = {
'robots': 'noindex',
'base_url': settings.BASE_URL,
'favicon': settings.FAVICON,
'theme': common.get_theme(request),
}
t = loader.get_template('404.html')
return HttpResponseNotFound(t.render(RequestContext(request, {'page': page})))
#
# XHR API
#
def api(request, **args):
cmd = args.get('cmd', '')
entry = request.POST.get('entry', None)
authed = request.user.is_authenticated() and request.user.is_staff
friend = request.user.is_authenticated() and not request.user.is_staff
if not authed and cmd != 'getcontent':
return HttpResponseForbidden()
if cmd == 'hide' and entry:
Entry.objects.filter(id=int(entry)).update(active=False)
elif cmd == 'unhide' and entry:
Entry.objects.filter(id=int(entry)).update(active=True)
elif cmd == 'gsc': # get selfposts classes
_srvs = Service.objects.filter (api='selfposts')\
.order_by('cls').values('id', 'cls')
srvs = {}
for item in _srvs:
if item['cls'] not in srvs:
srvs[item['cls']] = item
srvs = srvs.values()
d = []
for s in srvs:
d.append({'id': s['id'], 'cls': s['cls']})
return HttpResponse(json.dumps(d), mimetype='application/json')
elif cmd == 'share':
images = []
for i in range(0, 5):
img = request.POST.get('image' + str(i), None)
if img:
images.append(img)
source = request.POST.get('from', '')
entry = selfposts.API(False).share(
{'content': request.POST.get('content', ''),
'sid': request.POST.get('sid', None),
'draft': request.POST.get('draft', False),
'friends_only': request.POST.get('friends_only', False),
'link': request.POST.get('link', None),
'images': images,
'files': request.FILES,
'source': source,
'user': request.user})
if entry:
if not entry.draft:
pshb.publish()
if source == 'bookmarklet':
d = {'close_msg': _(
"You've successfully shared this web page at your stream.")}
return HttpResponse(json.dumps(d),
mimetype='application/json')
else:
entry.friends_only = False
if request.is_ajax():
return render_to_response('stream-pure.html',
{'entries': (entry,),
'authed': authed})
else:
return HttpResponseRedirect(settings.BASE_URL + '/')
elif cmd == 'reshare' and entry:
try:
entry = Entry.objects.get(id=int(entry))
if entry:
entry = selfposts.API(False).reshare(
entry, {'as_me': request.POST.get('as_me', False),
'user': request.user})
if entry:
pshb.publish()
return render_to_response('stream-pure.html',
{'entries': (entry,),
'authed': authed})
except Exception:
pass
elif cmd == 'favorite':
try:
entry = Entry.objects.get(id=int(entry))
if entry:
try:
fav = Favorite.objects.get(user=request.user, entry=entry)
except Favorite.DoesNotExist:
fav = Favorite(user=request.user, entry=entry)
fav.save()
media.transform_to_local(entry)
media.extract_and_register(entry)
entry.save()
except Exception:
pass
elif cmd == 'unfavorite':
try:
if entry:
entry = Entry.objects.get(id=int(entry))
if entry:
Favorite.objects.get(user=request.user,
entry=entry).delete()
except Exception:
pass
elif cmd == 'getcontent':
try:
if entry:
if not authed:
entry = Entry.objects.get(id=int(entry),
service__public=True)
else:
entry = Entry.objects.get(id=int(entry))
if entry:
if request.POST.get('raw', False) and authed:
return HttpResponse(entry.content)
if authed or friend:
entry.friends_only = False
content = fix_ampersands(gls_content('', entry))
return HttpResponse(content)
except Exception:
pass
elif cmd == 'putcontent':
try:
if entry and authed:
content = request.POST.get('content', '')
if content:
Entry.objects.filter(id=int(entry)).update(
content=content)
entry = Entry.objects.get(id=int(entry))
if entry:
content = fix_ampersands(gls_content('', entry))
return HttpResponse(content)
except Exception:
pass
return HttpResponse()