class FBInstantArticles(LatestEntriesFeed):
    feed_type = FBInstantFeed
    feed_items_number = get_setting("FEED_INSTANT_ITEMS")

    def items(self, obj=None):
        return Post.objects.namespace(self.namespace).published().order_by("-date_modified")[: self.feed_items_number]

    def _clean_html(self, content):
        body = BytesIO(content)
        document = etree.iterparse(body, html=True)
        for _a, element in document:
            if not (element.text and element.text.strip()) and len(element) == 0 and element.tag == "p":
                element.getparent().remove(element)
            if element.tag in ("h3", "h4", "h5", "h6") and "op-kicker" not in element.attrib.get("class", ""):
                element.tag = "h2"
        return etree.tostring(document.root)

    def item_extra_kwargs(self, item):
        if not item:
            return {}
        language = get_language_from_request(self.request, check_path=True)
        key = item.get_cache_key(language, "feed")
        content = cache.get(key)
        if not content:
            view = PostDetailView.as_view(instant_article=True)
            response = view(self.request, slug=item.safe_translation_getter("slug"))
            response.render()
            content = self._clean_html(response.content)
            cache.set(key, content, timeout=get_setting("FEED_CACHE_TIMEOUT"))
        if item.app_config.use_abstract:
            abstract = strip_tags(item.safe_translation_getter("abstract"))
        else:
            abstract = strip_tags(item.safe_translation_getter("post_text"))
        return {
            "author": item.get_author_name(),
            "content": content,
            "date": item.date_modified,
            "date_pub": item.date_modified,
            "date_mod": item.date_modified,
            "abstract": abstract,
        }

    def item_categories(self, item):
        return [category.safe_translation_getter("name") for category in item.categories.all()]

    def item_author_name(self, item):
        return ""

    def item_author_url(self, item):
        return ""

    def item_description(self, item):
        return None

    def item_pubdate(self, item):
        return None class LatestEntriesFeed(Feed):
    feed_type = Rss201rev2Feed
    feed_items_number = get_setting("FEED_LATEST_ITEMS")

    def __call__(self, request, *args, **kwargs):
        self.request = request
        self.namespace, self.config = get_app_instance(request)
        return super().__call__(request, *args, **kwargs)

    def link(self):
        return reverse("%s:posts-latest" % self.namespace, current_app=self.namespace)

    def title(self):
        return Site.objects.get_current().name

    def description(self):
        return _("Blog articles on %(site_name)s") % {"site_name": Site.objects.get_current().name}

    def items(self, obj=None):
        return Post.objects.namespace(self.namespace).published().order_by("-date_published")[: self.feed_items_number]

    def item_title(self, item):
        return mark_safe(item.safe_translation_getter("title"))

    def item_description(self, item):
        if item.app_config.use_abstract:
            return mark_safe(item.safe_translation_getter("abstract"))
        return mark_safe(item.safe_translation_getter("post_text"))

    def item_updateddate(self, item):
        return item.date_modified

    def item_pubdate(self, item):
        return item.date_published

    def item_guid(self, item):
        return item.guid

    def item_author_name(self, item):
        return item.get_author_name()

    def item_author_url(self, item):
        return item.get_author_url() class TagFeed(LatestEntriesFeed):
    feed_items_number = get_setting("FEED_TAGS_ITEMS")

    def get_object(self, request, tag):
        return tag  # pragma: no cover

    def items(self, obj=None):
        return Post.objects.published().filter(tags__slug=obj)[: self.feed_items_number] def get_setting(name):
    """Get setting value from django settings with fallback to globals defaults."""
    from django.conf import settings

    return getattr(settings, "BLOG_%s" % name, params["BLOG_%s" % name]) class AuthorEntriesView(BaseBlogListView, ListView):
    view_url_name = "djangocms_blog:posts-author"

    def get_queryset(self):
        qs = super().get_queryset()
        if "username" in self.kwargs:
            qs = qs.filter(**{"author__%s" % User.USERNAME_FIELD: self.kwargs["username"]})
        return self.optimize(qs)

    def get_context_data(self, **kwargs):
        kwargs["author"] = get_object_or_404(User, **{User.USERNAME_FIELD: self.kwargs.get("username")})
        context = super().get_context_data(**kwargs)
        return context class CategoryEntriesView(BaseBlogListView, ListView):
    _category = None
    view_url_name = "djangocms_blog:posts-category"

    @property
    def category(self):
        if not self._category:
            try:
                self._category = BlogCategory.objects.active_translations(
                    get_language(), slug=self.kwargs["category"]
                ).get()
            except BlogCategory.DoesNotExist:
                raise Http404
        return self._category

    def get(self, *args, **kwargs):
        # submit object to cms toolbar to get correct language switcher behavior
        if hasattr(self.request, "toolbar"):
            self.request.toolbar.set_object(self.category)
        return super().get(*args, **kwargs)

    def get_queryset(self):
        qs = super().get_queryset()
        if "category" in self.kwargs:
            qs = qs.filter(categories=self.category.pk)
        return self.optimize(qs)

    def get_context_data(self, **kwargs):
        kwargs["category"] = self.category
        context = super().get_context_data(**kwargs)
        context["meta"] = self.category.as_meta()
        return context class PostArchiveView(BaseBlogListView, ListView):
    date_field = "date_published"
    allow_empty = True
    allow_future = True
    view_url_name = "djangocms_blog:posts-archive"

    def get_queryset(self):
        qs = super().get_queryset()
        if "month" in self.kwargs:
            qs = qs.filter(**{"%s__month" % self.date_field: self.kwargs["month"]})
        if "year" in self.kwargs:
            qs = qs.filter(**{"%s__year" % self.date_field: self.kwargs["year"]})
        return self.optimize(qs)

    def get_context_data(self, **kwargs):
        kwargs["month"] = int(self.kwargs.get("month")) if "month" in self.kwargs else None
        kwargs["year"] = int(self.kwargs.get("year")) if "year" in self.kwargs else None
        if kwargs["year"]:
            kwargs["archive_date"] = now().replace(kwargs["year"], kwargs["month"] or 1, 1)
        context = super().get_context_data(**kwargs)
        return context class PostDetailView(TranslatableSlugMixin, BaseBlogView, DetailView):
    context_object_name = "post"
    base_template_name = "post_detail.html"
    slug_field = "slug"
    view_url_name = "djangocms_blog:post-detail"
    instant_article = False

    def liveblog_enabled(self):
        return self.object.enable_liveblog and apps.is_installed("djangocms_blog.liveblog")

    def get_template_names(self):
        if self.instant_article:
            template_path = (self.config and self.config.template_prefix) or "djangocms_blog"
            return os.path.join(template_path, "post_instant_article.html")
        else:
            return super().get_template_names()

    def get_queryset(self):
        queryset = self.model._default_manager.all()
        if not getattr(self.request, "toolbar", None) or not self.request.toolbar.edit_mode_active:
            queryset = queryset.published()
        return self.optimize(queryset)

    def get(self, *args, **kwargs):
        # submit object to cms to get corrent language switcher and selected category behavior
        if hasattr(self.request, "toolbar"):
            self.request.toolbar.set_object(self.get_object())
        return super().get(*args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["meta"] = self.get_object().as_meta()
        context["instant_article"] = self.instant_article
        context["use_placeholder"] = get_setting("USE_PLACEHOLDER")
        setattr(self.request, get_setting("CURRENT_POST_IDENTIFIER"), self.get_object())
        return context class PostListView(BaseBlogListView, ListView):
    view_url_name = "djangocms_blog:posts-latest" class TaggedListView(BaseBlogListView, ListView):
    view_url_name = "djangocms_blog:posts-tagged"

    def get_queryset(self):
        qs = super().get_queryset()
        return self.optimize(qs.filter(tags__slug=self.kwargs["tag"]))

    def get_context_data(self, **kwargs):
        kwargs["tagged_entries"] = self.kwargs.get("tag") if "tag" in self.kwargs else None
        context = super().get_context_data(**kwargs)
        return context
from django.urls import path
from .feeds import FBInstantArticles, LatestEntriesFeed, TagFeed
from .settings import get_setting
from .views import (
    AuthorEntriesView,
    CategoryEntriesView,
    PostArchiveView,
    PostDetailView,
    PostListView,
    TaggedListView,
)



def get_urls():
    urls = get_setting("PERMALINK_URLS")
    details = []
    for urlconf in urls.values():
        details.append(
            path(urlconf, PostDetailView.as_view(), name="post-detail"),
        )
    return details


detail_urls = get_urls()

# module-level app_name attribute as per django 1.9+
app_name = "djangocms_blog"
urlpatterns = [
    path("", PostListView.as_view(), name="posts-latest"),
    path("feed/", LatestEntriesFeed(), name="posts-latest-feed"),
    path("feed/fb/", FBInstantArticles(), name="posts-latest-feed-fb"),
    path("<int:year>/", PostArchiveView.as_view(), name="posts-archive"),
    path("<int:year>/<int:month>/", PostArchiveView.as_view(), name="posts-archive"),
    path("author/<str:username>/", AuthorEntriesView.as_view(), name="posts-author"),

    path("category/<str:category>/", CategoryEntriesView.as_view(), name="posts-category"),