import json import xml.etree.ElementTree as ET import ox 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 = [datetime.strptime('%s-W%s-1' % w, "%Y-W%W-%w").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()) elif request.user.is_staff: now = get_now() else: now = None week, archive = models.Item.public(now) context['items'] = week if archive.exists(): context['archive'] = '/_%s/' % get_monday(get_now() - timedelta(days=7)) 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 = int(date.strftime('%W')) year = int(year) archive_week = archive.filter(year=year, week=week).order_by('published') years = {} context['weeks'] = get_weeks(archive) years["2024"] = [] for week in get_weeks(archive): print(week) 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']).first() if extra: context['week_title'] = extra.title context['week_byline'] = extra.byline 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 %s at %s' % ( 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'''

{item.data['title']}

'''.strip() content = ET.SubElement(entry, "content") content.attrib['type'] = 'html' content.text = html feed.append(entry) return HttpResponse( '\n' + ET.tostring(feed).decode(), 'application/atom+xml' )