kopia lustrzana https://gitlab.com/marnanel/chapeau
196 wiersze
6.0 KiB
Python
196 wiersze
6.0 KiB
Python
# trilby_api/views/timelines.py
|
|
#
|
|
# Part of kepi.
|
|
# Copyright (c) 2018-2021 Marnanel Thurman.
|
|
# Licensed under the GNU Public License v2.
|
|
|
|
import logging
|
|
logger = logging.getLogger(name='kepi')
|
|
|
|
from django.db import IntegrityError, transaction
|
|
from django.shortcuts import render, get_object_or_404
|
|
from django.views import View
|
|
from django.http import HttpResponse, JsonResponse, Http404
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth.models import AnonymousUser
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.utils.datastructures import MultiValueDictKeyError
|
|
from django.core.exceptions import SuspiciousOperation
|
|
from django.conf import settings
|
|
import kepi.trilby_api.models as trilby_models
|
|
import kepi.trilby_api.utils as trilby_utils
|
|
from kepi.trilby_api.serializers import *
|
|
from rest_framework import generics, response, mixins
|
|
from rest_framework.permissions import IsAuthenticated, \
|
|
IsAuthenticatedOrReadOnly
|
|
from rest_framework.response import Response
|
|
from rest_framework.renderers import JSONRenderer
|
|
import kepi.trilby_api.receivers
|
|
from kepi.bowler_pub.utils import uri_to_url
|
|
import json
|
|
import re
|
|
import random
|
|
|
|
DEFAULT_TIMELINE_SLICE_LENGTH = 20
|
|
|
|
class AbstractTimeline(generics.ListAPIView):
|
|
|
|
serializer_class = StatusSerializer
|
|
permission_classes = [
|
|
IsAuthenticated,
|
|
]
|
|
|
|
def get_queryset(self):
|
|
raise NotImplementedError("cannot query abstract timeline")
|
|
|
|
def filter_queryset(self, queryset,
|
|
min_id = None,
|
|
max_id = None,
|
|
since_id = None,
|
|
local = False,
|
|
remote = False,
|
|
limit = DEFAULT_TIMELINE_SLICE_LENGTH,
|
|
*args, **kwargs,
|
|
):
|
|
|
|
logger.debug("Timeline queryset: %s", queryset)
|
|
|
|
if 'min_id' in self.request.query_params:
|
|
queryset = queryset.filter(
|
|
id__gte = int(self.request.query_params['min_id']),
|
|
)
|
|
logger.debug(" -- after min_id: %s", queryset)
|
|
|
|
if 'max_id' in self.request.query_params:
|
|
queryset = queryset.filter(
|
|
id__lte = int(self.request.query_params['max_id']),
|
|
)
|
|
logger.debug(" -- after max_id: %s", queryset)
|
|
|
|
if 'since_id' in self.request.query_params:
|
|
queryset = queryset.filter(
|
|
id__gt = int(self.request.query_params['since_id']),
|
|
)
|
|
logger.debug(" -- after since_id: %s", queryset)
|
|
|
|
if self.request.query_params.get('local', '')=='true':
|
|
queryset = queryset.filter(
|
|
remote_url__isnull = True,
|
|
)
|
|
logger.debug(" -- after local: %s", queryset)
|
|
|
|
if self.request.query_params.get('remote', '')=='true':
|
|
queryset = queryset.filter(
|
|
remote_url__isnull = False,
|
|
)
|
|
logger.debug(" -- after remote: %s", queryset)
|
|
|
|
if 'only_media' in self.request.query_params:
|
|
# We don't support media at present, so this will give us
|
|
# the empty set
|
|
queryset = queryset.none()
|
|
logger.debug(" -- after only_media: %s", queryset)
|
|
|
|
# Slicing the queryset must be done last,
|
|
# since running operations on a sliced queryset
|
|
# causes evaluation.
|
|
limit = int(self.request.query_params.get('limit',
|
|
default = DEFAULT_TIMELINE_SLICE_LENGTH,
|
|
))
|
|
|
|
queryset = queryset[:limit]
|
|
|
|
logger.debug(" -- after slice of %d: %s",
|
|
limit,
|
|
queryset,
|
|
)
|
|
|
|
return queryset
|
|
|
|
class PublicTimeline(AbstractTimeline):
|
|
|
|
permission_classes = ()
|
|
|
|
def get_queryset(self):
|
|
|
|
result = trilby_models.Status.objects.filter(
|
|
visibility = trilby_utils.VISIBILITY_PUBLIC,
|
|
)
|
|
|
|
return result
|
|
|
|
class HomeTimeline(AbstractTimeline):
|
|
|
|
permission_classes = [
|
|
IsAuthenticated,
|
|
]
|
|
|
|
def get_queryset(self):
|
|
|
|
result = self.request.user.localperson.inbox
|
|
|
|
logger.debug("Home timeline is %s",
|
|
result)
|
|
|
|
return result
|
|
|
|
########################################
|
|
|
|
class UserFeed(View):
|
|
|
|
permission_classes = ()
|
|
|
|
def get(self, request, username, *args, **kwargs):
|
|
|
|
try:
|
|
the_person = get_object_or_404(
|
|
self.get_queryset(),
|
|
id = int(kwargs['user']),
|
|
)
|
|
except ValueError:
|
|
return error_response(404, 'Non-decimal ID')
|
|
|
|
context = {
|
|
'self': request.build_absolute_uri(),
|
|
'user': the_person,
|
|
'statuses': the_person.outbox,
|
|
'server_name': settings.KEPI['LOCAL_OBJECT_HOSTNAME'],
|
|
}
|
|
|
|
result = render(
|
|
request=request,
|
|
template_name='account.atom.xml',
|
|
context=context,
|
|
content_type='application/atom+xml',
|
|
)
|
|
|
|
links = ', '.join(
|
|
[ '<{}>; rel="{}"; type="{}"'.format(
|
|
settings.KEPI[uri].format(
|
|
hostname = settings.KEPI['LOCAL_OBJECT_HOSTNAME'],
|
|
username = the_person.id[1:],
|
|
),
|
|
rel, mimetype)
|
|
for uri, rel, mimetype in
|
|
[
|
|
('USER_WEBFINGER_URLS',
|
|
'lrdd',
|
|
'application/xrd+xml',
|
|
),
|
|
|
|
('USER_FEED_URLS',
|
|
'alternate',
|
|
'application/atom+xml',
|
|
),
|
|
|
|
('USER_FEED_URLS',
|
|
'alternate',
|
|
'application/activity+json',
|
|
),
|
|
]
|
|
])
|
|
|
|
result['Link'] = links
|
|
|
|
return result
|