phantasmobile/app/item/views.py
2025-02-23 11:47:20 -05:00

266 lines
9.2 KiB
Python

import json
import xml.etree.ElementTree as ET
import ox
import isoweek
from django.utils import timezone
from django.utils.timezone import datetime, timedelta
from django.shortcuts import render, redirect
from django.db.models import Q
from django.utils.html import mark_safe
from django.conf import settings
from django.http import HttpResponse, Http404
from . import models
from . import tasks
from ..signalbot.rpc import send_reaction
from .utils import render_to_json
from ..utils import default_context
TS_FORMAT = "%Y-%m-%dT%H:%M:%S"
def get_now():
return timezone.make_aware(datetime.now(), timezone.get_default_timezone())
def get_monday(date):
d = date.strftime('%Y-W%W-1')
return datetime.strptime(d, "%Y-W%W-%w").strftime('%Y-%m-%d')
def format_week(week):
a = datetime.strptime(week, '%Y-%m-%d')
b = (a + timedelta(days=6))
fmt = '%b %d'
a = a.strftime(fmt)
b = b.strftime(fmt)
extra = models.Week.objects.filter(monday=week).first()
if extra and extra.title:
extra = ': ' + extra.title
else:
extra = ''
return '%s - %s%s' % (a, b, extra)
def get_byline(week):
extra = models.Week.objects.filter(monday=week).first()
if extra:
return extra.byline
def get_weeks(archive):
weeks = sorted(set(archive.values_list('year', 'week')))
weeks = [isoweek.Week(*w).monday().strftime('%Y-%m-%d') for w in weeks]
weeks = [{
'date': week,
'year': week.split('-')[0],
'title': format_week(week)
} for week in weeks]
return weeks
def index(request):
context = default_context(request)
now = request.GET.get("now")
if request.user.is_staff and now:
now = datetime.strptime(now, TS_FORMAT)
now = timezone.make_aware(now, timezone.get_default_timezone())
else:
now = get_now()
monday = get_monday(now)
week, archive = models.Item.public(now)
if archive and archive.exists():
context['archive'] = '/_%s/' % get_monday(now - timedelta(days=7))
if isinstance(week, models.Week) and week.is_break:
context["break"] = week
else:
context['items'] = week
extra = models.Week.objects.filter(monday=monday, is_break=False).first()
if extra:
context['week_background'] = extra.background(now, '-published')
if now:
context['now'] = now
context['previous_week'] = (now - timedelta(days=7)).strftime(TS_FORMAT)
context['next_week'] = (now + timedelta(days=7)).strftime(TS_FORMAT)
return render(request, 'index.html', context)
def archive(request, year=None, month=None, day=None, week=None):
context = default_context(request)
archive = models.Item.all_public()
if year and month and day:
date = datetime.strptime('%s-%s-%s' % (year, month, day), '%Y-%m-%d')
week = date.isocalendar()[1]
year = int(year)
archive_week = archive.filter(year=year, week=week).order_by('published')
years = {}
context['weeks'] = get_weeks(archive)
for week in get_weeks(archive):
if week["year"] not in years:
years[week["year"]] = []
years[week["year"]].append(week)
context['years'] = []
for year in reversed(sorted(years)):
context['years'].append({
'year': year,
'weeks': years[year]
})
context['this_week'] = date.strftime('%Y-%m-%d')
context['this_year'] = date.strftime('%Y')
extra = models.Week.objects.filter(monday=context['this_week'], is_break=False).first()
if extra:
context['week_title'] = extra.title
context['week_byline'] = extra.byline
context['week_background'] = extra.background()
elif week:
week = int(week)
year = int(year)
week = datetime.strptime('%s-W%s-1' % (year, week), "%Y-W%W-%w").strftime('%Y-%m-%d')
return redirect('/_%s/' % week)
elif year:
week = datetime.strptime('%s-W1-1' % year, "%Y-W%W-%w").strftime('%Y-%m-%d')
return redirect('/_%s/' % week)
context['items'] = archive_week
return render(request, 'archive.html', context)
def item(request, id):
context = default_context(request)
item = models.Item.objects.get(id=id)
if not request.user.is_staff and (
not item.published or item.published >= get_now()
):
raise Http404
context['item'] = item
context['url'] = request.build_absolute_uri(item.get_absolute_url())
qs = item.comments.order_by('created')
if not request.user.is_staff:
q = ~Q(published=None)
if request.user.is_authenticated:
q |= Q(user=request.user)
if request.session and request.session.session_key:
q |= Q(session_key=request.session.session_key)
qs = qs.filter(q)
comments = []
for comment in qs:
comments.append(comment.json())
context['comments'] = mark_safe(json.dumps(comments, ensure_ascii=False))
context['comments'] = json.dumps(comments, ensure_ascii=False)
user = {}
if request.user.is_staff:
user['is_moderator'] = True
if request.user.is_authenticated:
user['username'] = request.user.username
context['user'] = mark_safe(json.dumps(user))
request.session['item'] = id
qs = models.Item.objects.exclude(published=None).exclude(id=item.id)
if not request.user.is_staff:
now = get_now()
qs = qs.filter(published__lt=now)
previous_item = qs.exclude(published__gt=item.published).order_by('-published').first()
next_item = qs.exclude(published__lt=item.published).order_by('published').first()
if next_item:
context['next'] = next_item.get_absolute_url()
if previous_item:
context['previous'] = previous_item.get_absolute_url()
return render(request, 'item.html', context)
def comment(request):
response = {}
data = json.loads(request.body)
comment = models.Comment()
comment.item = models.Item.objects.get(id=data['item'])
if request.user.is_authenticated:
comment.user = request.user
if comment.user.has_perm('app.item.can_post_comment'):
comment.published = get_now()
else:
comment.name = data['name']
comment.email = data['email']
comment.session_key = request.session.session_key
comment.text = ox.add_links(data['text'])
comment.save()
link = request.build_absolute_uri(comment.item.get_absolute_url())
tasks.notify_moderators.delay(comment.id, link)
response = comment.json()
return render_to_json(response)
def publish_comment(request):
response = {}
data = json.loads(request.body)
if request.user.is_staff:
comment = models.Comment.objects.get(id=data['comment'])
comment.published = get_now()
comment.save()
if comment.data.get("moderator_ts"):
account = settings.SIGNAL_ACCOUNT
group = settings.SIGNAL_MODERATORS_GROUP
send_reaction(
account, comment.data["moderator_ts"], "🎉", group=group
)
link = request.build_absolute_uri(comment.item.get_absolute_url())
msg = '%s commented on <b>%s</b> at <a href="%s">%s</a>' % (
comment.name, comment.item.title, link, link
)
tasks.notify_telegram.delay(msg)
response['status'] = 'ok'
else:
response['error'] = 'permission denied'
return render_to_json(response)
def atom_xml(request):
feed = ET.Element("feed")
feed.attrib['xmlns'] = 'http://www.w3.org/2005/Atom'
feed.attrib['xmlns:media'] = 'http://search.yahoo.com/mrss/'
feed.attrib['xml:lang'] = 'en'
title = ET.SubElement(feed, "title")
title.text = settings.SITENAME
title.attrib['type'] = 'text'
link = ET.SubElement(feed, "link")
link.attrib['rel'] = 'self'
link.attrib['type'] = 'application/atom+xml'
atom_link = request.build_absolute_uri('/atom.xml')
link.attrib['href'] = atom_link
el = ET.SubElement(feed, 'id')
el.text = atom_link
week, archive = models.Item.public()
for item in week:
page_link = request.build_absolute_uri(item.get_absolute_url())
entry = ET.Element("entry")
title = ET.SubElement(entry, "title")
title.text = item.title
link = ET.SubElement(entry, "link")
link.attrib['rel'] = 'alternate'
link.attrib['href'] = page_link
updated = ET.SubElement(entry, "updated")
updated.text = item.modified.strftime("%Y-%m-%dT%H:%M:%SZ")
published = ET.SubElement(entry, "published")
published.text = item.created.strftime("%Y-%m-%dT%H:%M:%SZ")
el = ET.SubElement(entry, "id")
el.text = page_link
print(item.data)
if 'title' in item.data and 'thumbnail' in item.data:
html = f'''
<p>
{item.data['title']}
</p>
<img src={ item.data['thumbnail'] }>
'''.strip()
content = ET.SubElement(entry, "content")
content.attrib['type'] = 'html'
content.text = html
feed.append(entry)
return HttpResponse(
'<?xml version="1.0" encoding="utf-8" ?>\n' + ET.tostring(feed).decode(),
'application/atom+xml'
)