diff --git a/djangocms_blog/feeds.py b/djangocms_blog/feeds.py index 798f3dba..c42c7603 100644 --- a/djangocms_blog/feeds.py +++ b/djangocms_blog/feeds.py @@ -32,7 +32,7 @@ class LatestEntriesFeed(Feed): feed_type = Rss201rev2Feed - feed_items_number = get_setting('FEED_LATEST_ITEMS') + feed_items_number = get_setting("FEED_LATEST_ITEMS") def __call__(self, request, *args, **kwargs): self.request = request @@ -40,26 +40,30 @@ def __call__(self, request, *args, **kwargs): return super(LatestEntriesFeed, self).__call__(request, *args, **kwargs) def link(self): - return reverse('%s:posts-latest' % self.namespace, current_app=self.namespace) + 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} + 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] + 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')) + 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')) + 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 @@ -78,114 +82,145 @@ def item_author_url(self, item): class TagFeed(LatestEntriesFeed): - feed_items_number = get_setting('FEED_TAGS_ITEMS') + def get_object(self, request, tag, feed_items_number=None): + if feed_items_number is None: + feed_items_number = get_setting("FEED_TAGS_ITEMS") + + return {"tag": tag, "feed_items_number": int(feed_items_number)} + + def items(self, obj=None): + return Post.objects.published().filter(tags__slug=obj["tag"])[ + : obj["feed_items_number"] + ] + - def get_object(self, request, tag): - return tag # pragma: no cover +class CategoryFeed(LatestEntriesFeed): + def get_object(self, request, category, feed_items_number=None): + if feed_items_number is None: + feed_items_number = get_setting("FEED_CATEGORY_ITEMS") + + return {"category": category, "feed_items_number": int(feed_items_number)} def items(self, obj=None): - return Post.objects.published().filter(tags__slug=obj)[:self.feed_items_number] + return Post.objects.published().filter( + categories__translations__slug=obj["category"] + )[: obj["feed_items_number"]] class FBInstantFeed(Rss201rev2Feed): - date_format = '%Y-%m-%dT%H:%M:%S%z' + date_format = "%Y-%m-%dT%H:%M:%S%z" def rss_attributes(self): return { - 'version': self._version, - 'xmlns:content': 'http://purl.org/rss/1.0/modules/content/' + "version": self._version, + "xmlns:content": "http://purl.org/rss/1.0/modules/content/", } def add_root_elements(self, handler): - handler.addQuickElement('title', self.feed['title']) - handler.addQuickElement('link', self.feed['link']) - handler.addQuickElement('description', self.feed['description']) - if self.feed['language'] is not None: - handler.addQuickElement('language', self.feed['language']) - for cat in self.feed['categories']: - handler.addQuickElement('category', cat) - if self.feed['feed_copyright'] is not None: - handler.addQuickElement('copyright', self.feed['feed_copyright']) + handler.addQuickElement("title", self.feed["title"]) + handler.addQuickElement("link", self.feed["link"]) + handler.addQuickElement("description", self.feed["description"]) + if self.feed["language"] is not None: + handler.addQuickElement("language", self.feed["language"]) + for cat in self.feed["categories"]: + handler.addQuickElement("category", cat) + if self.feed["feed_copyright"] is not None: + handler.addQuickElement("copyright", self.feed["feed_copyright"]) handler.addQuickElement( - 'lastBuildDate', self.latest_post_date().strftime(self.date_format) + "lastBuildDate", self.latest_post_date().strftime(self.date_format) ) - if self.feed['ttl'] is not None: - handler.addQuickElement('ttl', self.feed['ttl']) + if self.feed["ttl"] is not None: + handler.addQuickElement("ttl", self.feed["ttl"]) def add_item_elements(self, handler, item): super(FBInstantFeed, self).add_item_elements(handler, item) - if item['author']: - handler.addQuickElement('author', item['author']) - if item['date_pub'] is not None: - handler.addQuickElement('pubDate', item['date_pub'].strftime(self.date_format)) - if item['date_mod'] is not None: - handler.addQuickElement('modDate', item['date_mod'].strftime(self.date_format)) - - handler.startElement('description', {}) - handler._write(''.format( - unescape(normalize_newlines(force_text(item['abstract'])).replace('\n', ' '))) + if item["author"]: + handler.addQuickElement("author", item["author"]) + if item["date_pub"] is not None: + handler.addQuickElement( + "pubDate", item["date_pub"].strftime(self.date_format) + ) + if item["date_mod"] is not None: + handler.addQuickElement( + "modDate", item["date_mod"].strftime(self.date_format) + ) + + handler.startElement("description", {}) + handler._write( + "".format( + unescape( + normalize_newlines(force_text(item["abstract"])).replace("\n", " ") + ) + ) ) - handler.endElement('description') - handler.startElement('content:encoded', {}) - handler._write('') - handler._write(unescape(force_text(item['content']))) - handler._write(']]>') - handler.endElement('content:encoded') + handler.endElement("description") + handler.startElement("content:encoded", {}) + handler._write("") + handler._write(unescape(force_text(item["content"]))) + handler._write("]]>") + handler.endElement("content:encoded") class FBInstantArticles(LatestEntriesFeed): feed_type = FBInstantFeed - feed_items_number = get_setting('FEED_INSTANT_ITEMS') + 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] + 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, e in document: - if not (e.text and e.text.strip()) and len(e) == 0 and e.tag == 'p': + if not (e.text and e.text.strip()) and len(e) == 0 and e.tag == "p": e.getparent().remove(e) - if e.tag in ('h3', 'h4', 'h5', 'h6') and 'op-kicker' not in e.attrib.get('class', ''): - e.tag = 'h2' + if e.tag in ("h3", "h4", "h5", "h6") and "op-kicker" not in e.attrib.get( + "class", "" + ): + e.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') + 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 = 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')) + cache.set(key, content, timeout=get_setting("FEED_CACHE_TIMEOUT")) if item.app_config.use_abstract: - abstract = strip_tags(item.safe_translation_getter('abstract')) + abstract = strip_tags(item.safe_translation_getter("abstract")) else: - abstract = strip_tags(item.safe_translation_getter('post_text')) + 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 + "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()] + return [ + category.safe_translation_getter("name") + for category in item.categories.all() + ] def item_author_name(self, item): - return '' + return "" def item_author_url(self, item): - return '' + return "" def item_description(self, item): return None diff --git a/djangocms_blog/models.py b/djangocms_blog/models.py index a63acd89..42a40ea9 100644 --- a/djangocms_blog/models.py +++ b/djangocms_blog/models.py @@ -562,7 +562,10 @@ def get_authors(self): qs = qs.published(current_site=False) count = qs.count() if count: + # total nb of articles author.count = count + # "the number of author articles to be displayed" + author.posts = qs[:self.latest_posts] return authors diff --git a/djangocms_blog/settings.py b/djangocms_blog/settings.py index 1567f6ee..98667f90 100644 --- a/djangocms_blog/settings.py +++ b/djangocms_blog/settings.py @@ -1,16 +1,16 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals -MENU_TYPE_COMPLETE = 'complete' -MENU_TYPE_CATEGORIES = 'categories' -MENU_TYPE_POSTS = 'posts' -MENU_TYPE_NONE = 'none' +MENU_TYPE_COMPLETE = "complete" +MENU_TYPE_CATEGORIES = "categories" +MENU_TYPE_POSTS = "posts" +MENU_TYPE_NONE = "none" DATE_FORMAT = "%a %d %b %Y %H:%M" -PERMALINK_TYPE_FULL_DATE = 'full_date' -PERMALINK_TYPE_SHORT_DATE = 'short_date' -PERMALINK_TYPE_CATEGORY = 'category' -PERMALINK_TYPE_SLUG = 'slug' +PERMALINK_TYPE_FULL_DATE = "full_date" +PERMALINK_TYPE_SHORT_DATE = "short_date" +PERMALINK_TYPE_CATEGORY = "category" +PERMALINK_TYPE_SLUG = "slug" def get_setting(name): @@ -19,146 +19,163 @@ def get_setting(name): from meta import settings as meta_settings PERMALINKS = ( - (PERMALINK_TYPE_FULL_DATE, _('Full date')), - (PERMALINK_TYPE_SHORT_DATE, _('Year / Month')), - (PERMALINK_TYPE_CATEGORY, _('Category')), - (PERMALINK_TYPE_SLUG, _('Just slug')), + (PERMALINK_TYPE_FULL_DATE, _("Full date")), + (PERMALINK_TYPE_SHORT_DATE, _("Year / Month")), + (PERMALINK_TYPE_CATEGORY, _("Category")), + (PERMALINK_TYPE_SLUG, _("Just slug")), ) PERMALINKS_URLS = { PERMALINK_TYPE_FULL_DATE: ( - r'^(?P\d{4})/(?P\d{1,2})/(?P\d{1,2})/(?P\w[-\w]*)/$' + r"^(?P\d{4})/(?P\d{1,2})/(?P\d{1,2})/(?P\w[-\w]*)/$" ), PERMALINK_TYPE_SHORT_DATE: ( - r'^(?P\d{4})/(?P\d{1,2})/(?P\w[-\w]*)/$' - ), - PERMALINK_TYPE_CATEGORY: ( - r'^(?P\w[-\w]*)/(?P\w[-\w]*)/$' - ), - PERMALINK_TYPE_SLUG: ( - r'^(?P\w[-\w]*)/$' + r"^(?P\d{4})/(?P\d{1,2})/(?P\w[-\w]*)/$" ), + PERMALINK_TYPE_CATEGORY: (r"^(?P\w[-\w]*)/(?P\w[-\w]*)/$"), + PERMALINK_TYPE_SLUG: (r"^(?P\w[-\w]*)/$"), } MENU_TYPES = ( - (MENU_TYPE_COMPLETE, _('Categories and posts')), - (MENU_TYPE_CATEGORIES, _('Categories only')), - (MENU_TYPE_POSTS, _('Posts only')), - (MENU_TYPE_NONE, _('None')), + (MENU_TYPE_COMPLETE, _("Categories and posts")), + (MENU_TYPE_CATEGORIES, _("Categories only")), + (MENU_TYPE_POSTS, _("Posts only")), + (MENU_TYPE_NONE, _("None")), ) SITEMAP_CHANGEFREQ_LIST = ( - ('always', _('always')), - ('hourly', _('hourly')), - ('daily', _('daily')), - ('weekly', _('weekly')), - ('monthly', _('monthly')), - ('yearly', _('yearly')), - ('never', _('never')), + ("always", _("always")), + ("hourly", _("hourly")), + ("daily", _("daily")), + ("weekly", _("weekly")), + ("monthly", _("monthly")), + ("yearly", _("yearly")), + ("never", _("never")), ) default = { - 'BLOG_IMAGE_THUMBNAIL_SIZE': getattr(settings, 'BLOG_IMAGE_THUMBNAIL_SIZE', { - 'size': '120x120', - 'crop': True, - 'upscale': False - }), - - 'BLOG_IMAGE_FULL_SIZE': getattr(settings, 'BLOG_IMAGE_FULL_SIZE', { - 'size': '640x120', - 'crop': True, - 'upscale': False - }), - - 'BLOG_URLCONF': getattr(settings, 'BLOG_URLCONF', 'djangocms_blog.urls'), - 'BLOG_PAGINATION': getattr(settings, 'BLOG_PAGINATION', 10), - 'BLOG_LATEST_POSTS': getattr(settings, 'BLOG_LATEST_POSTS', 5), - 'BLOG_POSTS_LIST_TRUNCWORDS_COUNT': getattr( - settings, 'BLOG_POSTS_LIST_TRUNCWORDS_COUNT', 100 - ), - 'BLOG_META_DESCRIPTION_LENGTH': getattr( - settings, 'BLOG_META_DESCRIPTION_LENGTH', 320 - ), - 'BLOG_META_TITLE_LENGTH': getattr( - settings, 'BLOG_META_TITLE_LENGTH', 70 - ), - 'BLOG_MENU_TYPES': MENU_TYPES, - 'BLOG_MENU_EMPTY_CATEGORIES': getattr(settings, 'MENU_EMPTY_CATEGORIES', True), - 'BLOG_TYPE': getattr(settings, 'BLOG_TYPE', 'Article'), - 'BLOG_TYPES': meta_settings.OBJECT_TYPES, - 'BLOG_FB_TYPE': getattr(settings, 'BLOG_FB_TYPE', 'Article'), - 'BLOG_FB_TYPES': getattr(settings, 'BLOG_FB_TYPES', meta_settings.FB_TYPES), - 'BLOG_FB_APPID': getattr(settings, 'BLOG_FB_APPID', meta_settings.FB_APPID), - 'BLOG_FB_PROFILE_ID': getattr(settings, 'BLOG_FB_PROFILE_ID', meta_settings.FB_PROFILE_ID), - 'BLOG_FB_PUBLISHER': getattr(settings, 'BLOG_FB_PUBLISHER', meta_settings.FB_PUBLISHER), - 'BLOG_FB_AUTHOR_URL': getattr(settings, 'BLOG_FB_AUTHOR_URL', 'get_author_url'), - 'BLOG_FB_AUTHOR': getattr(settings, 'BLOG_FB_AUTHOR', 'get_author_name'), - 'BLOG_TWITTER_TYPE': getattr(settings, 'BLOG_TWITTER_TYPE', 'summary'), - 'BLOG_TWITTER_TYPES': getattr(settings, 'BLOG_TWITTER_TYPES', meta_settings.TWITTER_TYPES), - 'BLOG_TWITTER_SITE': getattr(settings, 'BLOG_TWITTER_SITE', meta_settings.TWITTER_SITE), - 'BLOG_TWITTER_AUTHOR': getattr(settings, 'BLOG_TWITTER_AUTHOR', 'get_author_twitter'), - 'BLOG_GPLUS_TYPE': getattr(settings, 'BLOG_GPLUS_TYPE', 'Blog'), - 'BLOG_GPLUS_TYPES': getattr(settings, 'BLOG_GPLUS_TYPES', meta_settings.GPLUS_TYPES), - 'BLOG_GPLUS_AUTHOR': getattr(settings, 'BLOG_GPLUS_AUTHOR', 'get_author_gplus'), - 'BLOG_ENABLE_COMMENTS': getattr(settings, 'BLOG_ENABLE_COMMENTS', True), - 'BLOG_USE_ABSTRACT': getattr(settings, 'BLOG_USE_ABSTRACT', True), - 'BLOG_USE_PLACEHOLDER': getattr(settings, 'BLOG_USE_PLACEHOLDER', True), - 'BLOG_USE_RELATED': getattr(settings, 'BLOG_USE_RELATED', True), - 'BLOG_MULTISITE': getattr(settings, 'BLOG_MULTISITE', True), - 'BLOG_AUTHOR_DEFAULT': getattr(settings, 'BLOG_AUTHOR_DEFAULT', True), - 'BLOG_DEFAULT_PUBLISHED': getattr(settings, 'BLOG_DEFAULT_PUBLISHED', False), - 'BLOG_ADMIN_POST_FIELDSET_FILTER': getattr( - settings, 'BLOG_ADMIN_POST_FIELDSET_FILTER', False), - 'BLOG_AVAILABLE_PERMALINK_STYLES': getattr( - settings, 'BLOG_AVAILABLE_PERMALINK_STYLES', PERMALINKS - ), - 'BLOG_PERMALINK_URLS': getattr(settings, 'BLOG_PERMALINK_URLS', PERMALINKS_URLS), - 'BLOG_DEFAULT_OBJECT_NAME': getattr(settings, 'BLOG_DEFAULT_OBJECT_NAME', 'Article'), - - 'BLOG_AUTO_SETUP': getattr(settings, 'BLOG_AUTO_SETUP', True), - 'BLOG_AUTO_HOME_TITLE': getattr(settings, 'BLOG_AUTO_HOME_TITLE', 'Home'), - 'BLOG_AUTO_BLOG_TITLE': getattr(settings, 'BLOG_AUTO_BLOG_TITLE', 'Blog'), - 'BLOG_AUTO_APP_TITLE': getattr(settings, 'BLOG_AUTO_APP_TITLE', 'Blog'), - 'BLOG_AUTO_NAMESPACE': getattr(settings, 'BLOG_AUTO_NAMESPACE', 'Blog'), - - 'BLOG_SITEMAP_PRIORITY_DEFAULT': getattr(settings, 'BLOG_SITEMAP_PRIORITY_DEFAULT', '0.5'), - 'BLOG_SITEMAP_CHANGEFREQ': getattr( - settings, 'BLOG_SITEMAP_CHANGEFREQ', SITEMAP_CHANGEFREQ_LIST + "BLOG_IMAGE_THUMBNAIL_SIZE": getattr( + settings, + "BLOG_IMAGE_THUMBNAIL_SIZE", + {"size": "120x120", "crop": True, "upscale": False}, ), - 'BLOG_SITEMAP_CHANGEFREQ_DEFAULT': getattr( - settings, 'BLOG_SITEMAP_CHANGEFREQ_DEFAULT', 'monthly' + "BLOG_IMAGE_FULL_SIZE": getattr( + settings, + "BLOG_IMAGE_FULL_SIZE", + {"size": "640x120", "crop": True, "upscale": False}, + ), + "BLOG_URLCONF": getattr(settings, "BLOG_URLCONF", "djangocms_blog.urls"), + "BLOG_PAGINATION": getattr(settings, "BLOG_PAGINATION", 10), + "BLOG_LATEST_POSTS": getattr(settings, "BLOG_LATEST_POSTS", 5), + "BLOG_POSTS_LIST_TRUNCWORDS_COUNT": getattr( + settings, "BLOG_POSTS_LIST_TRUNCWORDS_COUNT", 100 + ), + "BLOG_META_DESCRIPTION_LENGTH": getattr( + settings, "BLOG_META_DESCRIPTION_LENGTH", 320 + ), + "BLOG_META_TITLE_LENGTH": getattr(settings, "BLOG_META_TITLE_LENGTH", 70), + "BLOG_MENU_TYPES": MENU_TYPES, + "BLOG_MENU_EMPTY_CATEGORIES": getattr(settings, "MENU_EMPTY_CATEGORIES", True), + "BLOG_TYPE": getattr(settings, "BLOG_TYPE", "Article"), + "BLOG_TYPES": meta_settings.OBJECT_TYPES, + "BLOG_FB_TYPE": getattr(settings, "BLOG_FB_TYPE", "Article"), + "BLOG_FB_TYPES": getattr(settings, "BLOG_FB_TYPES", meta_settings.FB_TYPES), + "BLOG_FB_APPID": getattr(settings, "BLOG_FB_APPID", meta_settings.FB_APPID), + "BLOG_FB_PROFILE_ID": getattr( + settings, "BLOG_FB_PROFILE_ID", meta_settings.FB_PROFILE_ID + ), + "BLOG_FB_PUBLISHER": getattr( + settings, "BLOG_FB_PUBLISHER", meta_settings.FB_PUBLISHER + ), + "BLOG_FB_AUTHOR_URL": getattr(settings, "BLOG_FB_AUTHOR_URL", "get_author_url"), + "BLOG_FB_AUTHOR": getattr(settings, "BLOG_FB_AUTHOR", "get_author_name"), + "BLOG_TWITTER_TYPE": getattr(settings, "BLOG_TWITTER_TYPE", "summary"), + "BLOG_TWITTER_TYPES": getattr( + settings, "BLOG_TWITTER_TYPES", meta_settings.TWITTER_TYPES + ), + "BLOG_TWITTER_SITE": getattr( + settings, "BLOG_TWITTER_SITE", meta_settings.TWITTER_SITE + ), + "BLOG_TWITTER_AUTHOR": getattr( + settings, "BLOG_TWITTER_AUTHOR", "get_author_twitter" + ), + "BLOG_GPLUS_TYPE": getattr(settings, "BLOG_GPLUS_TYPE", "Blog"), + "BLOG_GPLUS_TYPES": getattr( + settings, "BLOG_GPLUS_TYPES", meta_settings.GPLUS_TYPES + ), + "BLOG_GPLUS_AUTHOR": getattr(settings, "BLOG_GPLUS_AUTHOR", "get_author_gplus"), + "BLOG_ENABLE_COMMENTS": getattr(settings, "BLOG_ENABLE_COMMENTS", True), + "BLOG_USE_ABSTRACT": getattr(settings, "BLOG_USE_ABSTRACT", True), + "BLOG_USE_PLACEHOLDER": getattr(settings, "BLOG_USE_PLACEHOLDER", True), + "BLOG_USE_RELATED": getattr(settings, "BLOG_USE_RELATED", True), + "BLOG_MULTISITE": getattr(settings, "BLOG_MULTISITE", True), + "BLOG_AUTHOR_DEFAULT": getattr(settings, "BLOG_AUTHOR_DEFAULT", True), + "BLOG_DEFAULT_PUBLISHED": getattr(settings, "BLOG_DEFAULT_PUBLISHED", False), + "BLOG_ADMIN_POST_FIELDSET_FILTER": getattr( + settings, "BLOG_ADMIN_POST_FIELDSET_FILTER", False + ), + "BLOG_AVAILABLE_PERMALINK_STYLES": getattr( + settings, "BLOG_AVAILABLE_PERMALINK_STYLES", PERMALINKS + ), + "BLOG_PERMALINK_URLS": getattr( + settings, "BLOG_PERMALINK_URLS", PERMALINKS_URLS + ), + "BLOG_DEFAULT_OBJECT_NAME": getattr( + settings, "BLOG_DEFAULT_OBJECT_NAME", "Article" + ), + "BLOG_AUTO_SETUP": getattr(settings, "BLOG_AUTO_SETUP", True), + "BLOG_AUTO_HOME_TITLE": getattr(settings, "BLOG_AUTO_HOME_TITLE", "Home"), + "BLOG_AUTO_BLOG_TITLE": getattr(settings, "BLOG_AUTO_BLOG_TITLE", "Blog"), + "BLOG_AUTO_APP_TITLE": getattr(settings, "BLOG_AUTO_APP_TITLE", "Blog"), + "BLOG_AUTO_NAMESPACE": getattr(settings, "BLOG_AUTO_NAMESPACE", "Blog"), + "BLOG_SITEMAP_PRIORITY_DEFAULT": getattr( + settings, "BLOG_SITEMAP_PRIORITY_DEFAULT", "0.5" + ), + "BLOG_SITEMAP_CHANGEFREQ": getattr( + settings, "BLOG_SITEMAP_CHANGEFREQ", SITEMAP_CHANGEFREQ_LIST + ), + "BLOG_SITEMAP_CHANGEFREQ_DEFAULT": getattr( + settings, "BLOG_SITEMAP_CHANGEFREQ_DEFAULT", "monthly" + ), + "BLOG_ENABLE_SEARCH": getattr(settings, "BLOG_ENABLE_SEARCH", True), + "BLOG_CURRENT_POST_IDENTIFIER": getattr( + settings, "BLOG_CURRENT_POST_IDENTIFIER", "djangocms_post_current" + ), + "BLOG_CURRENT_NAMESPACE": getattr( + settings, "BLOG_CURRENT_NAMESPACE", "djangocms_post_current_config" + ), + "BLOG_ENABLE_THROUGH_TOOLBAR_MENU": getattr( + settings, "BLOG_ENABLE_THROUGH_TOOLBAR_MENU", False + ), + "BLOG_PLUGIN_MODULE_NAME": getattr( + settings, "BLOG_PLUGIN_MODULE_NAME", _("Blog") + ), + "BLOG_LATEST_ENTRIES_PLUGIN_NAME": getattr( + settings, "BLOG_LATEST_ENTRIES_PLUGIN_NAME", _("Latest Blog Articles") + ), + "BLOG_LATEST_ENTRIES_PLUGIN_NAME_CACHED": getattr( + settings, + "BLOG_LATEST_ENTRIES_PLUGIN_NAME_CACHED", + _("Latest Blog Articles - Cache"), + ), + "BLOG_AUTHOR_POSTS_PLUGIN_NAME": getattr( + settings, "BLOG_AUTHOR_POSTS_PLUGIN_NAME", _("Author Blog Articles") + ), + "BLOG_TAGS_PLUGIN_NAME": getattr(settings, "BLOG_TAGS_PLUGIN_NAME", _("Tags")), + "BLOG_CATEGORY_PLUGIN_NAME": getattr( + settings, "BLOG_CATEGORY_PLUGIN_NAME", _("Categories") + ), + "BLOG_ARCHIVE_PLUGIN_NAME": getattr( + settings, "BLOG_ARCHIVE_PLUGIN_NAME", _("Archive") + ), + "BLOG_FEED_CACHE_TIMEOUT": getattr(settings, "BLOG_FEED_CACHE_TIMEOUT", 3600), + "BLOG_FEED_INSTANT_ITEMS": getattr(settings, "BLOG_FEED_INSTANT_ITEMS", 50), + "BLOG_FEED_LATEST_ITEMS": getattr(settings, "BLOG_FEED_LATEST_ITEMS", 10), + "BLOG_FEED_TAGS_ITEMS": getattr(settings, "BLOG_FEED_TAGS_ITEMS", 10), + "BLOG_FEED_CATEGORY_ITEMS": getattr(settings, "BLOG_FEED_CATEGORY_ITEMS", 10), + "BLOG_LIVEBLOG_PLUGINS": getattr( + settings, "BLOG_LIVEBLOG_PLUGINS", ("LiveblogPlugin",) + ), + "BLOG_PLUGIN_TEMPLATE_FOLDERS": getattr( + settings, + "BLOG_PLUGIN_TEMPLATE_FOLDERS", + (("plugins", _("Default template")),), ), - - 'BLOG_ENABLE_SEARCH': getattr(settings, 'BLOG_ENABLE_SEARCH', True), - 'BLOG_CURRENT_POST_IDENTIFIER': getattr( - settings, 'BLOG_CURRENT_POST_IDENTIFIER', 'djangocms_post_current'), - 'BLOG_CURRENT_NAMESPACE': getattr( - settings, 'BLOG_CURRENT_NAMESPACE', 'djangocms_post_current_config'), - 'BLOG_ENABLE_THROUGH_TOOLBAR_MENU': getattr( - settings, 'BLOG_ENABLE_THROUGH_TOOLBAR_MENU', False), - - 'BLOG_PLUGIN_MODULE_NAME': getattr(settings, 'BLOG_PLUGIN_MODULE_NAME', _('Blog')), - 'BLOG_LATEST_ENTRIES_PLUGIN_NAME': getattr( - settings, 'BLOG_LATEST_ENTRIES_PLUGIN_NAME', _('Latest Blog Articles')), - 'BLOG_LATEST_ENTRIES_PLUGIN_NAME_CACHED': getattr( - settings, 'BLOG_LATEST_ENTRIES_PLUGIN_NAME_CACHED', _('Latest Blog Articles - Cache')), - 'BLOG_AUTHOR_POSTS_PLUGIN_NAME': getattr( - settings, 'BLOG_AUTHOR_POSTS_PLUGIN_NAME', _('Author Blog Articles')), - 'BLOG_TAGS_PLUGIN_NAME': getattr( - settings, 'BLOG_TAGS_PLUGIN_NAME', _('Tags')), - 'BLOG_CATEGORY_PLUGIN_NAME': getattr( - settings, 'BLOG_CATEGORY_PLUGIN_NAME', _('Categories')), - 'BLOG_ARCHIVE_PLUGIN_NAME': getattr( - settings, 'BLOG_ARCHIVE_PLUGIN_NAME', _('Archive')), - 'BLOG_FEED_CACHE_TIMEOUT': getattr( - settings, 'BLOG_FEED_CACHE_TIMEOUT', 3600), - 'BLOG_FEED_INSTANT_ITEMS': getattr( - settings, 'BLOG_FEED_INSTANT_ITEMS', 50), - 'BLOG_FEED_LATEST_ITEMS': getattr( - settings, 'BLOG_FEED_LATEST_ITEMS', 10), - 'BLOG_FEED_TAGS_ITEMS': getattr( - settings, 'BLOG_FEED_TAGS_ITEMS', 10), - 'BLOG_LIVEBLOG_PLUGINS': getattr( - settings, 'BLOG_LIVEBLOG_PLUGINS', ('LiveblogPlugin',)), - - 'BLOG_PLUGIN_TEMPLATE_FOLDERS': getattr( - settings, 'BLOG_PLUGIN_TEMPLATE_FOLDERS', (('plugins', _('Default template')),)), - } - return default['BLOG_%s' % name] + return default["BLOG_%s" % name] diff --git a/djangocms_blog/urls.py b/djangocms_blog/urls.py index 522d7a36..e4ef5cbc 100644 --- a/djangocms_blog/urls.py +++ b/djangocms_blog/urls.py @@ -3,7 +3,7 @@ from django.conf.urls import url -from .feeds import FBInstantArticles, LatestEntriesFeed, TagFeed +from .feeds import CategoryFeed, FBInstantArticles, LatestEntriesFeed, TagFeed from .settings import get_setting from .views import ( AuthorEntriesView, CategoryEntriesView, PostArchiveView, PostDetailView, PostListView, @@ -12,36 +12,52 @@ def get_urls(): - urls = get_setting('PERMALINK_URLS') + urls = get_setting("PERMALINK_URLS") details = [] for urlconf in urls.values(): - details.append( - url(urlconf, PostDetailView.as_view(), name='post-detail'), - ) + details.append(url(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' +app_name = "djangocms_blog" urlpatterns = [ - url(r'^$', - PostListView.as_view(), name='posts-latest'), - url(r'^feed/$', - LatestEntriesFeed(), name='posts-latest-feed'), - url(r'^feed/fb/$', - FBInstantArticles(), name='posts-latest-feed-fb'), - url(r'^(?P\d{4})/$', - PostArchiveView.as_view(), name='posts-archive'), - url(r'^(?P\d{4})/(?P\d{1,2})/$', - PostArchiveView.as_view(), name='posts-archive'), - url(r'^author/(?P[\w\.@+-]+)/$', - AuthorEntriesView.as_view(), name='posts-author'), - url(r'^category/(?P[\w\.@+-]+)/$', - CategoryEntriesView.as_view(), name='posts-category'), - url(r'^tag/(?P[-\w]+)/$', - TaggedListView.as_view(), name='posts-tagged'), - url(r'^tag/(?P[-\w]+)/feed/$', - TagFeed(), name='posts-tagged-feed'), + url(r"^$", PostListView.as_view(), name="posts-latest"), + url(r"^feed/$", LatestEntriesFeed(), name="posts-latest-feed"), + url(r"^feed/fb/$", FBInstantArticles(), name="posts-latest-feed-fb"), + url(r"^(?P\d{4})/$", PostArchiveView.as_view(), name="posts-archive"), + url( + r"^(?P\d{4})/(?P\d{1,2})/$", + PostArchiveView.as_view(), + name="posts-archive", + ), + url( + r"^author/(?P[\w\.@+-]+)/$", + AuthorEntriesView.as_view(), + name="posts-author", + ), + url( + r"^category/(?P[\w\.@+-]+)/$", + CategoryEntriesView.as_view(), + name="posts-category", + ), + url( + r"^category/(?P[\w\.@+-]+)/feed/$", + CategoryFeed(), + name="posts-category-feed", + ), + url( + r"^category/(?P[\w\.@+-]+)/feed/(?P\d{1,4})/$", + CategoryFeed(), + name="posts-category-feed-items-number", + ), + url(r"^tag/(?P[-\w]+)/$", TaggedListView.as_view(), name="posts-tagged"), + url(r"^tag/(?P[-\w]+)/feed/$", TagFeed(), name="posts-tagged-feed"), + url( + r"^tag/(?P[-\w]+)/feed/(?P\d{1,4})/$", + TagFeed(), + name="posts-tagged-feed-items-number", + ), ] + detail_urls diff --git a/docs/development.rst b/docs/development.rst index 0b42a0de..fac78d0d 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -26,8 +26,8 @@ policies. These include: -* `guidelines and policies - `_ for contributing +* `development policies + `_ for contributing to the project, including standards for code and documentation * standards for `managing the project's development `_ diff --git a/docs/settings.rst b/docs/settings.rst index fadcb3e5..c75ad877 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -93,7 +93,8 @@ Global Settings * BLOG_FEED_CACHE_TIMEOUT: Cache timeout for RSS feeds * BLOG_FEED_INSTANT_ITEMS: Number of items in Instant Article feed * BLOG_FEED_LATEST_ITEMS: Number of items in latest items feed -* BLOG_FEED_TAGS_ITEMS: Number of items in per tags feed +* BLOG_FEED_TAGS_ITEMS: Number of items in per tags feed (default: ``10``) +* BLOG_FEED_CATEGORY_ITEMS: Number of items in per category feed (default: ``10``) * BLOG_PLUGIN_TEMPLATE_FOLDERS: (Sub-)folder from which the plugin templates are loaded. The default folder is ``plugins``. It goes into the ``djangocms_blog`` template folder (or, if set, the folder named in the app hook). This allows, e.g., different templates for showing a post list as tables, columns, ... . New templates have the same names as the standard templates in the ``plugins`` folder (``latest_entries.html``, ``authors.html``, ``tags.html``, ``categories.html``, ``archive.html``). Default behavior corresponds to this setting being ``( ("plugins", _("Default template") )``. To add new templates add to this setting, e.g., ``('timeline', _('Vertical timeline') )``. * BLOG_META_DESCRIPTION_LENGTH: Maximum length for the Meta description field (default: ``320``) * BLOG_META_TITLE_LENGTH: Maximum length for the Meta title field (default: ``70``)