소스 검색

Merge pull request #3 from mediacms-io/feat-search-rss

introduce rss and custom rss
Markos Gogoulos 4 년 전
부모
커밋
fed0234034
6개의 변경된 파일173개의 추가작업 그리고 14개의 파일을 삭제
  1. 1 0
      files/context_processors.py
  2. 150 6
      files/feeds.py
  3. 10 5
      files/management_views.py
  4. 3 2
      files/urls.py
  5. 8 1
      files/views.py
  6. 1 0
      templates/common/head-links.html

+ 1 - 0
files/context_processors.py

@@ -37,4 +37,5 @@ def stuff(request):
     ret[
         "VIDEO_PLAYER_FEATURED_VIDEO_ON_INDEX_PAGE"
     ] = settings.VIDEO_PLAYER_FEATURED_VIDEO_ON_INDEX_PAGE
+    ret["RSS_URL"] = "/rss"
     return ret

+ 150 - 6
files/feeds.py

@@ -1,20 +1,72 @@
 from django.contrib.syndication.views import Feed
+from django.utils.feedgenerator import Rss201rev2Feed
 from django.urls import reverse
 from django.db.models import Q
+from django.conf import settings
+from django.contrib.postgres.search import SearchQuery
 
-from .models import Media
+from .models import Media, Category
+from . import helpers
+from .stop_words import STOP_WORDS
 
 
-class RssMediaFeed(Feed):
+class MediaRSSFeed(Rss201rev2Feed):
+    def rss_attributes(self):
+        attrs = super(MediaRSSFeed, self).rss_attributes()
+        attrs["xmlns:media"] = "http://search.yahoo.com/mrss/"
+        attrs["xmlns:atom"] = "http://www.w3.org/2005/Atom"
+        return attrs
+
+    def add_item_elements(self, handler, item):
+        """Callback to add elements to each item (item/entry) element."""
+        super(MediaRSSFeed, self).add_item_elements(handler, item)
+
+        if "media:title" in item:
+            handler.addQuickElement("media:title", item["title"])
+        if "media:description" in item:
+            handler.addQuickElement("media:description", item["description"])
+
+        if "content_url" in item:
+            content = dict(url=item["content_url"])
+            if "content_width" in item:
+                content["width"] = str(item["content_width"])
+            if "content_height" in item:
+                content["height"] = str(item["content_height"])
+            handler.addQuickElement("media:content", "", content)
+
+        if "thumbnail_url" in item:
+            thumbnail = dict(url=item["thumbnail_url"])
+            if "thumbnail_width" in item:
+                thumbnail["width"] = str(item["thumbnail_width"])
+            if "thumbnail_height" in item:
+                thumbnail["height"] = str(item["thumbnail_height"])
+            handler.addQuickElement("media:thumbnail", "", thumbnail)
+
+        if "keywords" in item:
+            handler.addQuickElement("media:keywords", item["keywords"])
+
+    def add_root_elements(self, handler):
+        super().add_root_elements(handler)
+        if self.feed["author_name"] is not None:
+            handler.startElement("author", {})
+            handler.addQuickElement("name", self.feed["author_name"])
+            handler.endElement("author")
+        if self.feed.get("published") is not None:
+            handler.startElement("published", {})
+            handler.addQuickElement("name", self.feed["published"])
+            handler.endElement("published")
+
+
+class IndexRSSFeed(Feed):
+    feed_type = MediaRSSFeed
     title = "Latest Media"
-    link = "/media"
+    link = "/rss"
     description = "Latest Media RSS feed"
 
     def items(self):
-        basic_query = Q(listable=True)
-        media = Media.objects.filter(basic_query).order_by("-add_date")
+        media = Media.objects.filter(listable=True).order_by("-add_date")
         media = media.prefetch_related("user")
-        return media[:40]
+        return media[:20]
 
     def item_title(self, item):
         return item.title
@@ -22,5 +74,97 @@ class RssMediaFeed(Feed):
     def item_description(self, item):
         return item.description
 
+    def item_author_name(self, item):
+        return item.user.username
+
+    def item_pubdate(self, item):
+        return item.add_date
+
+    def item_updateddate(self, item):
+        return item.edit_date
+
     def item_link(self, item):
         return reverse("get_media") + "?m={0}".format(item.friendly_token)
+
+    def item_extra_kwargs(self, item):
+        item = {
+            "media:title": item.title,
+            "media:description": item.description,
+            "content_width": 720,
+            "thumbnail_url": f"{settings.SSL_FRONTEND_HOST}/{item.poster_url}",
+            "content_url": f"{settings.SSL_FRONTEND_HOST}/{item.get_absolute_url()}",
+            "thumbnail_width": 720,
+        }
+        return item
+
+
+class SearchRSSFeed(Feed):
+    feed_type = MediaRSSFeed
+    description = "Latest Media RSS feed"
+
+    def link(self, obj):
+        return f"/rss/search"
+
+    def get_object(self, request):
+        category = request.GET.get("c", "")
+        tag = request.GET.get("t", "")
+        query = request.GET.get("q", "")
+
+        media = Media.objects.filter(listable=True)
+
+        if category:
+            media = media.filter(category__title=category)
+        elif tag:
+            media = media.filter(tags__title=tag)
+        elif query:
+            # same as on files.views.MediaSearch: move this processing to a prepare_query function
+            query = helpers.clean_query(query)
+            q_parts = [
+                q_part.rstrip("y")
+                for q_part in query.split()
+                if q_part not in STOP_WORDS
+            ]
+            if q_parts:
+                query = SearchQuery(q_parts[0] + ":*", search_type="raw")
+                for part in q_parts[1:]:
+                    query &= SearchQuery(part + ":*", search_type="raw")
+            else:
+                query = None
+        if query:
+            media = media.filter(search=query)
+
+        media = media.order_by("-add_date").prefetch_related("user")
+
+        return media
+
+    def items(self, objects):
+        return objects[:20]
+
+    def item_title(self, item):
+        return item.title
+
+    def item_description(self, item):
+        return item.description
+
+    def item_author_name(self, item):
+        return item.user.username
+
+    def item_pubdate(self, item):
+        return item.add_date
+
+    def item_updateddate(self, item):
+        return item.edit_date
+
+    def item_link(self, item):
+        return reverse("get_media") + "?m={0}".format(item.friendly_token)
+
+    def item_extra_kwargs(self, item):
+        item = {
+            "media:title": item.title,
+            "media:description": item.description,
+            "content_width": 720,
+            "thumbnail_url": f"{settings.SSL_FRONTEND_HOST}/{item.poster_url}",
+            "content_url": f"{settings.SSL_FRONTEND_HOST}/{item.get_absolute_url()}",
+            "thumbnail_width": 720,
+        }
+        return item

+ 10 - 5
files/management_views.py

@@ -137,11 +137,10 @@ class CommentList(APIView):
         serializer = CommentSerializer(page, many=True, context={"request": request})
         return paginator.get_paginated_response(serializer.data)
 
-
     def delete(self, request, format=None):
-        comment_ids = request.GET.get('comment_ids')
+        comment_ids = request.GET.get("comment_ids")
         if comment_ids:
-            comments = comment_ids.split(',')
+            comments = comment_ids.split(",")
             Comment.objects.filter(uid__in=comments).delete()
         return Response(status=status.HTTP_204_NO_CONTENT)
 
@@ -161,6 +160,7 @@ class UserList(APIView):
         params = self.request.query_params
         ordering = params.get("ordering", "").strip()
         sort_by = params.get("sort_by", "").strip()
+        role = params.get("role", "all").strip()
 
         sort_by_options = ["date_added", "name"]
         if sort_by not in sort_by_options:
@@ -173,11 +173,16 @@ class UserList(APIView):
         pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
 
         qs = User.objects.filter()
-        media = qs.order_by(f"{ordering}{sort_by}")
+        if role == "manager":
+            qs = qs.filter(is_manager=True)
+        elif role == "editor":
+            qs = qs.filter(is_editor=True)
+
+        users = qs.order_by(f"{ordering}{sort_by}")
 
         paginator = pagination_class()
 
-        page = paginator.paginate_queryset(media, request)
+        page = paginator.paginate_queryset(users, request)
 
         serializer = UserSerializer(page, many=True, context={"request": request})
         return paginator.get_paginated_response(serializer.data)

+ 3 - 2
files/urls.py

@@ -5,7 +5,7 @@ from django.urls import path
 
 from . import views
 from . import management_views
-from .feeds import RssMediaFeed
+from .feeds import IndexRSSFeed, SearchRSSFeed
 
 urlpatterns = [
     url(r"^$", views.index),
@@ -33,7 +33,8 @@ urlpatterns = [
     ),
     url(r"^popular$", views.recommended_media),
     url(r"^recommended$", views.recommended_media),
-    path("rss/", RssMediaFeed()),
+    path("rss/", IndexRSSFeed()),
+    url("^rss/search", SearchRSSFeed()),
     url(r"^search", views.search, name="search"),
     url(r"^scpublisher", views.upload_media, name="upload_media"),
     url(r"^tags", views.tags, name="tags"),

+ 8 - 1
files/views.py

@@ -296,6 +296,8 @@ def search(request):
     """Search view"""
 
     context = {}
+    RSS_URL = f"/rss{request.environ['REQUEST_URI']}"
+    context["RSS_URL"] = RSS_URL
     return render(request, "cms/search.html", context)
 
 
@@ -730,8 +732,13 @@ class MediaSearch(APIView):
         media = Media.objects.filter(state="public", is_reviewed=True)
 
         if query:
+            # move this processing to a prepare_query function
             query = clean_query(query)
-            q_parts = [q_part for q_part in query.split() if q_part not in STOP_WORDS]
+            q_parts = [
+                q_part.rstrip("y")
+                for q_part in query.split()
+                if q_part not in STOP_WORDS
+            ]
             if q_parts:
                 query = SearchQuery(q_parts[0] + ":*", search_type="raw")
                 for part in q_parts[1:]:

+ 1 - 0
templates/common/head-links.html

@@ -5,6 +5,7 @@
 		<link rel="manifest" href="{% static "favicons/site.webmanifest" %}">
 		<link rel="mask-icon" href="{% static "favicons/safari-pinned-tab.svg" %}" color="#009933">
 		<link rel="shortcut icon" href="{% static "favicons/favicon.ico" %}">
+		<link rel="alternate" type="application/rss+xml" title="RSS feeds" href="{{RSS_URL}}" />
 		<meta name="msapplication-TileColor" content="#ffffff">
 		<meta name="msapplication-config" content="{% static "favicons/browserconfig.xml" %}">
 		<meta name="theme-color" content="#ffffff">