2023-09-26 17:44:38 +00:00
|
|
|
import json
|
2023-07-25 19:03:54 +00:00
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
2023-09-26 17:44:38 +00:00
|
|
|
import ox
|
2023-07-24 11:05:45 +00:00
|
|
|
|
|
|
|
from django.utils import timezone
|
2023-08-14 12:10:30 +00:00
|
|
|
from django.utils.timezone import datetime, timedelta
|
2023-08-31 16:05:27 +00:00
|
|
|
from django.shortcuts import render, redirect
|
2023-07-24 11:05:45 +00:00
|
|
|
from django.db.models import Q
|
|
|
|
from django.utils.html import mark_safe
|
|
|
|
from django.conf import settings
|
2023-08-16 15:40:42 +00:00
|
|
|
from django.http import HttpResponse, Http404
|
2023-07-15 07:30:36 +00:00
|
|
|
|
|
|
|
from . import models
|
2023-07-24 11:05:45 +00:00
|
|
|
from . import tasks
|
|
|
|
from ..signalbot.rpc import send_reaction
|
|
|
|
from .utils import render_to_json
|
2023-07-26 09:50:09 +00:00
|
|
|
from ..utils import default_context
|
2023-07-15 07:30:36 +00:00
|
|
|
|
2023-08-14 12:10:30 +00:00
|
|
|
TS_FORMAT = "%Y-%m-%dT%H:%M:%S"
|
|
|
|
|
2023-07-15 07:30:36 +00:00
|
|
|
|
2023-08-16 15:40:42 +00:00
|
|
|
def get_now():
|
|
|
|
return timezone.make_aware(datetime.now(), timezone.get_default_timezone())
|
|
|
|
|
|
|
|
|
2023-08-31 16:05:27 +00:00
|
|
|
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)
|
2023-08-31 17:24:52 +00:00
|
|
|
extra = models.Week.objects.filter(monday=week).first()
|
2023-12-03 14:13:23 +00:00
|
|
|
if extra and extra.title:
|
2023-08-31 17:24:52 +00:00
|
|
|
extra = ': ' + extra.title
|
|
|
|
else:
|
|
|
|
extra = ''
|
|
|
|
return '%s - %s%s' % (a, b, extra)
|
2023-08-31 16:05:27 +00:00
|
|
|
|
2024-02-06 16:47:54 +00:00
|
|
|
def get_byline(week):
|
|
|
|
extra = models.Week.objects.filter(monday=week).first()
|
|
|
|
if extra:
|
|
|
|
return extra.byline
|
2023-08-31 16:05:27 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
2023-07-15 07:30:36 +00:00
|
|
|
def index(request):
|
2023-07-26 09:50:09 +00:00
|
|
|
context = default_context(request)
|
2023-08-14 12:10:30 +00:00
|
|
|
now = request.GET.get("now")
|
|
|
|
if request.user.is_staff and now:
|
|
|
|
now = datetime.strptime(now, TS_FORMAT)
|
2023-08-14 21:33:23 +00:00
|
|
|
now = timezone.make_aware(now, timezone.get_default_timezone())
|
2023-08-14 12:10:30 +00:00
|
|
|
elif request.user.is_staff:
|
2023-08-16 15:40:42 +00:00
|
|
|
now = get_now()
|
2023-08-14 12:10:30 +00:00
|
|
|
else:
|
|
|
|
now = None
|
|
|
|
week, archive = models.Item.public(now)
|
2023-07-15 07:30:36 +00:00
|
|
|
context['items'] = week
|
2023-08-23 12:44:37 +00:00
|
|
|
if archive.exists():
|
2023-08-31 16:05:27 +00:00
|
|
|
context['archive'] = '/_%s/' % get_monday(get_now() - timedelta(days=7))
|
2023-08-14 12:10:30 +00:00
|
|
|
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)
|
2023-07-15 07:30:36 +00:00
|
|
|
return render(request, 'index.html', context)
|
|
|
|
|
|
|
|
|
2023-08-31 16:05:27 +00:00
|
|
|
def archive(request, year=None, month=None, day=None, week=None):
|
2023-07-26 09:50:09 +00:00
|
|
|
context = default_context(request)
|
2023-10-01 07:08:09 +00:00
|
|
|
archive = models.Item.all_public()
|
2023-08-31 16:05:27 +00:00
|
|
|
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')
|
2024-01-26 11:52:26 +00:00
|
|
|
years = {}
|
2023-08-31 16:05:27 +00:00
|
|
|
context['weeks'] = get_weeks(archive)
|
2024-01-26 11:52:26 +00:00
|
|
|
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]
|
|
|
|
})
|
2023-08-31 16:05:27 +00:00
|
|
|
context['this_week'] = date.strftime('%Y-%m-%d')
|
|
|
|
context['this_year'] = date.strftime('%Y')
|
2023-08-31 17:24:52 +00:00
|
|
|
extra = models.Week.objects.filter(monday=context['this_week']).first()
|
|
|
|
if extra:
|
|
|
|
context['week_title'] = extra.title
|
2024-02-06 16:47:54 +00:00
|
|
|
context['week_byline'] = extra.byline
|
2023-08-31 16:05:27 +00:00
|
|
|
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
|
2023-07-15 07:30:36 +00:00
|
|
|
return render(request, 'archive.html', context)
|
|
|
|
|
2023-07-24 11:05:45 +00:00
|
|
|
|
2023-07-15 07:30:36 +00:00
|
|
|
def item(request, id):
|
2023-07-26 09:50:09 +00:00
|
|
|
context = default_context(request)
|
2023-07-15 07:30:36 +00:00
|
|
|
item = models.Item.objects.get(id=id)
|
2023-08-16 15:40:42 +00:00
|
|
|
if not request.user.is_staff and (
|
|
|
|
not item.published or item.published >= get_now()
|
|
|
|
):
|
|
|
|
raise Http404
|
2023-07-15 07:30:36 +00:00
|
|
|
context['item'] = item
|
2023-08-17 10:27:49 +00:00
|
|
|
context['url'] = request.build_absolute_uri(item.get_absolute_url())
|
2023-07-24 11:05:45 +00:00
|
|
|
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:
|
2023-07-24 21:00:43 +00:00
|
|
|
comments.append(comment.json())
|
2023-08-23 12:44:37 +00:00
|
|
|
context['comments'] = mark_safe(json.dumps(comments, ensure_ascii=False))
|
|
|
|
context['comments'] = json.dumps(comments, ensure_ascii=False)
|
|
|
|
|
2023-07-24 11:05:45 +00:00
|
|
|
user = {}
|
|
|
|
if request.user.is_staff:
|
|
|
|
user['is_moderator'] = True
|
|
|
|
if request.user.is_authenticated:
|
|
|
|
user['username'] = request.user.username
|
2023-07-15 07:30:36 +00:00
|
|
|
|
2023-07-24 11:05:45 +00:00
|
|
|
context['user'] = mark_safe(json.dumps(user))
|
|
|
|
request.session['item'] = id
|
2023-08-23 12:44:37 +00:00
|
|
|
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()
|
|
|
|
|
2023-07-24 11:05:45 +00:00
|
|
|
return render(request, 'item.html', context)
|
2023-07-15 07:30:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
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
|
2023-07-24 11:05:45 +00:00
|
|
|
if comment.user.has_perm('app.item.can_post_comment'):
|
2023-08-16 15:40:42 +00:00
|
|
|
comment.published = get_now()
|
2023-07-15 07:30:36 +00:00
|
|
|
else:
|
|
|
|
comment.name = data['name']
|
|
|
|
comment.email = data['email']
|
2023-07-24 11:05:45 +00:00
|
|
|
comment.session_key = request.session.session_key
|
2023-09-26 17:44:38 +00:00
|
|
|
comment.text = ox.add_links(data['text'])
|
2023-07-15 07:30:36 +00:00
|
|
|
comment.save()
|
2023-07-25 19:03:54 +00:00
|
|
|
link = request.build_absolute_uri(comment.item.get_absolute_url())
|
|
|
|
tasks.notify_moderators.delay(comment.id, link)
|
2023-07-15 07:30:36 +00:00
|
|
|
response = comment.json()
|
|
|
|
return render_to_json(response)
|
2023-07-24 11:05:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
def publish_comment(request):
|
|
|
|
response = {}
|
|
|
|
data = json.loads(request.body)
|
|
|
|
if request.user.is_staff:
|
|
|
|
comment = models.Comment.objects.get(id=data['comment'])
|
2023-08-16 15:40:42 +00:00
|
|
|
comment.published = get_now()
|
2023-07-24 11:05:45 +00:00
|
|
|
comment.save()
|
|
|
|
if comment.data.get("moderator_ts"):
|
|
|
|
account = settings.SIGNAL_ACCOUNT
|
|
|
|
group = settings.SIGNAL_MODERATORS_GROUP
|
2023-07-25 19:03:54 +00:00
|
|
|
send_reaction(
|
|
|
|
account, comment.data["moderator_ts"], "🎉", group=group
|
|
|
|
)
|
2023-08-31 16:12:34 +00:00
|
|
|
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)
|
2023-07-24 11:05:45 +00:00
|
|
|
response['status'] = 'ok'
|
|
|
|
else:
|
|
|
|
response['error'] = 'permission denied'
|
|
|
|
return render_to_json(response)
|
2023-07-25 19:03:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
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'
|
|
|
|
)
|
|
|
|
|