diff --git a/docs/content.rst b/docs/content.rst index 2c88741d..24f91900 100644 --- a/docs/content.rst +++ b/docs/content.rst @@ -533,9 +533,9 @@ your settings file. Publishing drafts ================= -If you want to publish an article as a draft (for friends to review before -publishing, for example), you can add a ``Status: draft`` attribute to its -metadata. That article will then be output to the ``drafts`` folder and not +If you want to publish an article or a page as a draft (for friends to review +before publishing, for example), you can add a ``Status: draft`` attribute to +its metadata. That article will then be output to the ``drafts`` folder and not listed on the index page nor on any category or tag page. If your articles should be automatically published as a draft (to not accidentally diff --git a/docs/settings.rst b/docs/settings.rst index dbd960d5..a4fc0ba5 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -445,6 +445,24 @@ respectively. The location we will save the page which doesn't use the default language. +.. data:: DRAFT_PAGE_URL = 'drafts/pages/{slug}.html' + + The URL used to link to a page draft. + +.. data:: DRAFT_PAGE_SAVE_AS = 'drafts/pages/{slug}.html' + + The actual location a page draft is saved at. + +.. data:: DRAFT_PAGE_LANG_URL = 'drafts/pages/{slug}-{lang}.html' + + The URL used to link to a page draft which doesn't use the default + language. + +.. data:: DRAFT_PAGE_LANG_SAVE_AS = 'drafts/pages/{slug}-{lang}.html' + + The actual location a page draft which doesn't use the default language is + saved at. + .. data:: CATEGORY_URL = 'category/{slug}.html' The URL to use for a category. diff --git a/docs/themes.rst b/docs/themes.rst index 98d11bd3..e94ff08e 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -86,6 +86,7 @@ categories A list of (category, articles) tuples, containing all the categories and corresponding articles (values) pages The list of pages hidden_pages The list of hidden pages +draft_pages The list of draft pages ============= =================================================== @@ -423,7 +424,7 @@ metadata Page header metadata `dict`. save_as Location to save the page. slug Page slug. source_path Full system path of the page source file. -status The page status, can be any of 'published' or +status The page status, can be any of 'published', 'hidden' or 'draft'. summary Rendered summary content. tags List of :ref:`Tag ` diff --git a/pelican/__init__.py b/pelican/__init__.py index 8dfbb7ba..c00bc591 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -212,13 +212,20 @@ class Pelican(object): len(pages_generator.hidden_translations)), 'hidden page', 'hidden pages') + pluralized_draft_pages = maybe_pluralize( + (len(pages_generator.draft_pages) + + len(pages_generator.draft_translations)), + 'draft page', + 'draft pages') - print('Done: Processed {}, {}, {} and {} in {:.2f} seconds.'.format( - pluralized_articles, - pluralized_drafts, - pluralized_pages, - pluralized_hidden_pages, - time.time() - start_time)) + print('Done: Processed {}, {}, {}, {} and {} in {:.2f} seconds.' + .format( + pluralized_articles, + pluralized_drafts, + pluralized_pages, + pluralized_hidden_pages, + pluralized_draft_pages, + time.time() - start_time)) def get_generator_classes(self): generators = [ArticlesGenerator, PagesGenerator] diff --git a/pelican/contents.py b/pelican/contents.py index 03ce0a43..14dfc89b 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -444,10 +444,14 @@ class Content(object): class Page(Content): mandatory_properties = ('title',) - allowed_statuses = ('published', 'hidden') + allowed_statuses = ('published', 'hidden', 'draft') default_status = 'published' default_template = 'page' + def _expand_settings(self, key): + klass = 'draft_page' if self.status == 'draft' else None + return super(Page, self)._expand_settings(key, klass) + class Article(Content): mandatory_properties = ('title', 'date', 'category') @@ -472,7 +476,7 @@ class Article(Content): self.date = SafeDatetime.max def _expand_settings(self, key): - klass = 'article' if self.status == 'published' else 'draft' + klass = 'draft' if self.status == 'draft' else 'article' return super(Article, self)._expand_settings(key, klass) diff --git a/pelican/generators.py b/pelican/generators.py index 069da0c1..d176e4ee 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -656,14 +656,18 @@ class PagesGenerator(CachingGenerator): def __init__(self, *args, **kwargs): self.pages = [] + self.translations = [] self.hidden_pages = [] self.hidden_translations = [] + self.draft_pages = [] + self.draft_translations = [] super(PagesGenerator, self).__init__(*args, **kwargs) signals.page_generator_init.send(self) def generate_context(self): all_pages = [] hidden_pages = [] + draft_pages = [] for f in self.get_files( self.settings['PAGE_PATHS'], exclude=self.settings['PAGE_EXCLUDES']): @@ -694,14 +698,18 @@ class PagesGenerator(CachingGenerator): all_pages.append(page) elif page.status == "hidden": hidden_pages.append(page) + elif page.status == "draft": + draft_pages.append(page) self.add_source_path(page) self.pages, self.translations = process_translations(all_pages) self.pages = order_content(self.pages, self.settings['PAGE_ORDER_BY']) self.hidden_pages, self.hidden_translations = \ process_translations(hidden_pages) + self.draft_pages, self.draft_translations = \ + process_translations(draft_pages) - self._update_context(('pages', 'hidden_pages')) + self._update_context(('pages', 'hidden_pages', 'draft_pages')) self.save_cache() self.readers.save_cache() @@ -709,7 +717,8 @@ class PagesGenerator(CachingGenerator): def generate_output(self, writer): for page in chain(self.translations, self.pages, - self.hidden_translations, self.hidden_pages): + self.hidden_translations, self.hidden_pages, + self.draft_translations, self.draft_pages): signals.page_generator_write_page.send(self, content=page) writer.write_file( page.save_as, self.get_template(page.template), @@ -722,7 +731,9 @@ class PagesGenerator(CachingGenerator): def refresh_metadata_intersite_links(self): for e in chain(self.pages, self.hidden_pages, - self.hidden_translations): + self.hidden_translations, + self.draft_pages, + self.draft_translations): if hasattr(e, 'refresh_metadata_intersite_links'): e.refresh_metadata_intersite_links() diff --git a/pelican/settings.py b/pelican/settings.py index 6849249e..b6f481d2 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -80,6 +80,11 @@ DEFAULT_CONFIG = { 'PAGE_ORDER_BY': 'basename', 'PAGE_LANG_URL': 'pages/{slug}-{lang}.html', 'PAGE_LANG_SAVE_AS': posix_join('pages', '{slug}-{lang}.html'), + 'DRAFT_PAGE_URL': 'drafts/pages/{slug}.html', + 'DRAFT_PAGE_SAVE_AS': posix_join('drafts', 'pages', '{slug}.html'), + 'DRAFT_PAGE_LANG_URL': 'drafts/pages/{slug}-{lang}.html', + 'DRAFT_PAGE_LANG_SAVE_AS': posix_join('drafts', 'pages', + '{slug}-{lang}.html'), 'STATIC_URL': '{path}', 'STATIC_SAVE_AS': '{path}', 'STATIC_CREATE_LINKS': False, diff --git a/pelican/tests/TestPages/draft_page.rst b/pelican/tests/TestPages/draft_page.rst new file mode 100644 index 00000000..19ca0646 --- /dev/null +++ b/pelican/tests/TestPages/draft_page.rst @@ -0,0 +1,8 @@ +This is a test draft page +########################## + +:status: draft + +The quick brown fox . + +This page is a draft. diff --git a/pelican/tests/TestPages/draft_page_markdown.md b/pelican/tests/TestPages/draft_page_markdown.md new file mode 100644 index 00000000..fda71868 --- /dev/null +++ b/pelican/tests/TestPages/draft_page_markdown.md @@ -0,0 +1,12 @@ +title: This is a markdown test draft page +status: draft + +Test Markdown File Header +========================= + +Used for pelican test +--------------------- + +The quick brown fox . + +This page is a draft \ No newline at end of file diff --git a/pelican/tests/TestPages/draft_page_with_template.rst b/pelican/tests/TestPages/draft_page_with_template.rst new file mode 100644 index 00000000..9d46e717 --- /dev/null +++ b/pelican/tests/TestPages/draft_page_with_template.rst @@ -0,0 +1,11 @@ +This is a test draft page with a custom template +################################################# + +:status: draft +:template: custom + +The quick brown fox . + +This page is a draft + +This page has a custom template to be called when rendered diff --git a/pelican/tests/test_cache.py b/pelican/tests/test_cache.py index a0cc49b7..72b2b557 100644 --- a/pelican/tests/test_cache.py +++ b/pelican/tests/test_cache.py @@ -71,6 +71,7 @@ class TestCache(unittest.TestCase): generator.generate_context() uncached_pages = sorted_titles(generator.pages) uncached_hidden_pages = sorted_titles(generator.hidden_pages) + uncached_draft_pages = sorted_titles(generator.draft_pages) generator = PagesGenerator( context=settings.copy(), settings=settings, @@ -78,9 +79,11 @@ class TestCache(unittest.TestCase): generator.generate_context() cached_pages = sorted_titles(generator.pages) cached_hidden_pages = sorted_titles(generator.hidden_pages) + cached_draft_pages = sorted_titles(generator.draft_pages) self.assertEqual(uncached_pages, cached_pages) self.assertEqual(uncached_hidden_pages, cached_hidden_pages) + self.assertEqual(uncached_draft_pages, cached_draft_pages) def test_reader_caching(self): """Test that cached and uncached content is same in reader level""" diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py index c1899ab8..52efe7fa 100644 --- a/pelican/tests/test_generators.py +++ b/pelican/tests/test_generators.py @@ -601,6 +601,7 @@ class TestPageGenerator(unittest.TestCase): generator.generate_context() pages = self.distill_pages(generator.pages) hidden_pages = self.distill_pages(generator.hidden_pages) + draft_pages = self.distill_pages(generator.draft_pages) pages_expected = [ ['This is a test page', 'published', 'page'], @@ -614,7 +615,13 @@ class TestPageGenerator(unittest.TestCase): ['This is a test hidden page', 'hidden', 'page'], ['This is a markdown test hidden page', 'hidden', 'page'], ['This is a test hidden page with a custom template', 'hidden', - 'custom'] + 'custom'], + ] + draft_pages_expected = [ + ['This is a test draft page', 'draft', 'page'], + ['This is a markdown test draft page', 'draft', 'page'], + ['This is a test draft page with a custom template', 'draft', + 'custom'], ] self.assertEqual(sorted(pages_expected), sorted(pages)) @@ -622,9 +629,13 @@ class TestPageGenerator(unittest.TestCase): sorted(pages_expected), sorted(self.distill_pages(generator.context['pages']))) self.assertEqual(sorted(hidden_pages_expected), sorted(hidden_pages)) + self.assertEqual(sorted(draft_pages_expected), sorted(draft_pages)) self.assertEqual( sorted(hidden_pages_expected), sorted(self.distill_pages(generator.context['hidden_pages']))) + self.assertEqual( + sorted(draft_pages_expected), + sorted(self.distill_pages(generator.context['draft_pages']))) def test_generate_sorted(self): settings = get_settings(filenames={})