Merge lp:~davidc3/developer-ubuntu-com/1471160_publication into lp:~dholbach/developer-ubuntu-com/1471160

Proposed by David Callé on 2015-07-16
Status: Merged
Merged at revision: 136
Proposed branch: lp:~davidc3/developer-ubuntu-com/1471160_publication
Merge into: lp:~dholbach/developer-ubuntu-com/1471160
Diff against target: 186 lines (+92/-27)
1 file modified
developer_portal/management/commands/import-snappy-branches.py (+92/-27)
To merge this branch: bzr merge lp:~davidc3/developer-ubuntu-com/1471160_publication
Reviewer Review Type Date Requested Status
Daniel Holbach 2015-07-16 Approve on 2015-07-16
Review via email: mp+264968@code.launchpad.net

Description of the Change

This is the publication part of the Snappy doc importer. Here is the whole process:

1) The previously imported documentation is removed

2) The importer gets new branches

3) A page is created for each branch at "snappy/guides/<alias>"
-- These pages are not visible in navigation
-- The "current" page redirects to "snappy/guides"
-- FIXME these pages are currently empty

4) Each set of docs is published under its own <alias> namespace
-- eg."snappy/guides/rolling/<doc>", "snappy/guides/current/<doc>", etc.
-- They are visible in navigation when the user is at:
--- "snappy/guides/<alias>" and "snappy/guides/<alias>/<doc>"

5) Redirects are created for "snappy/guides/<doc>" to "snappy/guides/current/<doc>"
-- They are visible in navigation when user at "snappy/guides"

To post a comment you must log in.
137. By David Callé on 2015-07-16

Make page titles more explicit about the origin of the doc

Daniel Holbach (dholbach) wrote :

Replace filename.split('/')[-1] with os.path.basename(filename) maybe.

138. By David Callé on 2015-07-16

Replace filename.split(/)[-1] with os.path.basename(filename)

Daniel Holbach (dholbach) wrote :

_slugify could probably be a function as opposed to being a method.

Daniel Holbach (dholbach) wrote :

How does updating of articles work? Will a new page be created nonetheless or does create_page() work similarly to get_or_create()?

review: Needs Information
Daniel Holbach (dholbach) wrote :

One file with the title "Cross Build.Md" was imported.

review: Needs Fixing
David Callé (davidc3) wrote :

Pages are created from scratch each time, since everything existing is removed when the importer starts, this way we don't have leftovers when a page is removed or renamed in branches.

Daniel Holbach (dholbach) wrote :

"Back to the latest stable release ›" link does not work.

review: Needs Fixing
David Callé (davidc3) wrote :

That's a fix for the doc branch, afaict :) (unless we want to deal with wrongly formatted/named pages, but I think we shouldn't and enforce a strict "docs doesn't break" policy upstream)

David Callé (davidc3) wrote :

"Back to the latest stable release ›" link does not work.

Can you paste one of these here ? I have things like "http://127.0.0.1:8000/snappy/guides/current/security" that work fine

Daniel Holbach (dholbach) wrote :

<div class="box pull-three three-col"><p>You are browsing the Snappy <code>rolling</code> documentation.</p><p><a>Back to the latest stable release ›</a></p></div>
<div class="eight-col">

Daniel Holbach (dholbach) wrote :

"Cross Build.Md" → "Cross Build" as a fallback maybe?

David Callé (davidc3) wrote :

Huh, that's an odd paste...

Not sure about the fallback. We can cater for this specific case, sure, but seeing doc names such as "The hashes.yaml file" makes me think we shouldn't try to sanitize, but fix it upstream. If the doc is wrongly formatted, let's not pretend it isn't.

Daniel Holbach (dholbach) wrote :

For "Cross Build.Md" this might fix it:

return os.path.basename(self.fn).replace('-', ' ').title()

return _slugify(self.fn).replace('-', ' ').title()

... or something?

139. By David Callé on 2015-07-16

Slugify misc fixes

David Callé (davidc3) wrote :

Sounds good to me. Fixed + made it a function.

Daniel Holbach (dholbach) wrote :

I'll merge this now and will just add a couple of FIXME entries. These branches are still WIP anyway.

Thanks a lot. Truly fantastic work!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'developer_portal/management/commands/import-snappy-branches.py'
2--- developer_portal/management/commands/import-snappy-branches.py 2015-07-14 14:23:46 +0000
3+++ developer_portal/management/commands/import-snappy-branches.py 2015-07-16 12:56:40 +0000
4@@ -13,34 +13,26 @@
5
6 from developer_portal.models import SnappyDocsBranch
7
8+RELEASE_PAGES = {}
9+
10
11 class MarkdownFile():
12 html = None
13- cms_path = None
14+ cms_path = ''
15
16 def __init__(self, fn):
17 self.fn = fn
18- self.html_fn = self.fn.replace('.md', '.html')
19+ self.slug = slugify(self.fn)
20 with codecs.open(self.fn, 'r', encoding='utf-8') as f:
21 self.html = markdown.markdown(f.read(), output_format="html5")
22+ self.release_alias = self._get_release_alias()
23 self.title = self._read_title()
24 self._remove_body_and_html_tags()
25 self._use_developer_site_style()
26- self._construct_cms_path()
27
28- def _construct_cms_path(self):
29- # /tmp/tmpnkFy7S/rolling/docs/hashes.html
30- # ->
31- # snappy/guides/rolling/hashes
32- #
33- # /tmp/tmpnkFy7S/current/docs/autopilot.html
34- # ->
35- # snappy/guides/autopilot
36- self.cms_path = 'snappy/guides/'
37- alias = re.findall(r'/tmp/tmp\S+?/(\S+?)/docs/\S+?.html', self.html_fn)
38- if alias and alias != ['current']:
39- self.cms_path += alias[0] + '/'
40- self.cms_path += os.path.basename(self.html_fn).replace('.html', '')
41+ def _get_release_alias(self):
42+ alias = re.findall(r'/tmp/tmp\S+?/(\S+?)/docs/\S+?', self.fn)
43+ return alias[0]
44
45 def _read_title(self):
46 soup = BeautifulSoup(self.html, 'html5lib')
47@@ -48,7 +40,7 @@
48 return soup.title.text
49 if soup.h1:
50 return soup.h1.text
51- return os.path.basename(self.fn).replace('-', ' ').title()
52+ return slugify(self.fn).replace('-', ' ').title()
53
54 def _remove_body_and_html_tags(self):
55 self.html = re.sub(r"<html>\n\s<body>\n", "", self.html,
56@@ -57,7 +49,20 @@
57 flags=re.MULTILINE)
58
59 def _use_developer_site_style(self):
60- begin = u"<div class=\"row no-border\">\n<div class=\"eight-col\">\n"
61+ # Make sure the reader knows which documentation she is browsing
62+ if self.release_alias != "current":
63+ begin = (u"<div class=\"row no-border\">\n"
64+ "<div class=\"box pull-three three-col\">"
65+ "<p>You are browsing the Snappy <code>%s</code> "
66+ "documentation.</p>"
67+ "<p><a href=\"/snappy/guides/current/%s\">"
68+ "Back to the latest stable release &rsaquo;"
69+ "</a></p></div>\n"
70+ "<div class=\"eight-col\">\n") % (self.release_alias,
71+ self.slug, )
72+ else:
73+ begin = (u"<div class=\"row no-border\">"
74+ "\n<div class=\"eight-col\">\n")
75 end = u"</div>\n</div>"
76 self.html = begin + self.html + end
77 self.html = self.html.replace(
78@@ -69,17 +74,39 @@
79
80 def replace_links(self, titles):
81 for title in titles:
82- sluggified_fn = os.path.basename(title).replace('.md', '')
83- url = u"https://developer.ubuntu.com/snappy/guides/%s" % \
84- sluggified_fn
85+ url = u"/snappy/guides/%s/%s" % (
86+ self.release_alias, slugify(title))
87 link = u"<a href=\"%s\">%s</a>" % (url, titles[title])
88 self.html = self.html.replace(os.path.basename(title), link)
89
90- def save(self):
91- # XXX: can likely be dropped - we don't want to write HTML files
92- # we want the HTML to be in the database
93- with codecs.open(self.html_fn, "w", encoding='utf-8') as t:
94- t.write(self.html)
95+ def publish(self):
96+ '''Publishes pages in their branch alias namespace.'''
97+ from cms.api import create_page, add_plugin
98+
99+ page_title = self.title
100+
101+ if self.release_alias == "current":
102+ # Add a guides/<page> redirect to guides/current/<page>
103+ page = create_page(
104+ self.title, "default.html", "en",
105+ slug=self.slug, parent=RELEASE_PAGES['guides_page'],
106+ in_navigation=True, position="last-child",
107+ redirect="/snappy/guides/current/%s" % (self.slug))
108+ page.publish('en')
109+ else:
110+ page_title += " (%s)" % (self.release_alias,)
111+
112+ page = create_page(
113+ page_title, "default.html", "en", slug=self.slug,
114+ menu_title=self.title, parent=RELEASE_PAGES[self.release_alias],
115+ in_navigation=True, position="last-child")
116+ placeholder = page.placeholders.get()
117+ add_plugin(placeholder, 'RawHtmlPlugin', 'en', body=self.html)
118+ page.publish('en')
119+
120+
121+def slugify(filename):
122+ return os.path.basename(filename).replace('.md', '')
123
124
125 def get_branch_from_lp(origin, alias):
126@@ -103,7 +130,43 @@
127 self.titles[md_file.fn] = md_file.title
128 for md_file in self.md_files:
129 md_file.replace_links(self.titles)
130- md_file.save()
131+ md_file.publish()
132+
133+
134+def remove_old_pages():
135+ '''Removes all pages in snappy/guides, created by the importer.'''
136+ from cms.models import Title, Page
137+
138+ pages_to_remove = []
139+ for g in Title.objects.select_related('page__id').filter(
140+ path__regex="snappy/guides/.*"):
141+ pages_to_remove.append(g.page.id)
142+ Page.objects.filter(id__in=pages_to_remove, created_by="script").delete()
143+
144+
145+def refresh_landing_page(release_alias):
146+ '''Creates a branch page at snappy/guides/<branch alias>.'''
147+ from cms.api import create_page
148+ from cms.models import Title
149+
150+ guides_page = Title.objects.filter(
151+ path="snappy/guides", published=True,
152+ language="en", publisher_is_draft=True)[0]
153+ RELEASE_PAGES['guides_page'] = guides_page.page
154+
155+ if release_alias == "current":
156+ redirect = "/snappy/guides"
157+ else:
158+ redirect = None
159+ new_release_page = create_page(
160+ release_alias, "default.html", "en", slug=release_alias,
161+ parent=RELEASE_PAGES['guides_page'], in_navigation=False,
162+ position="last-child", redirect=redirect)
163+ # FIXME Page needs content
164+ #placeholder = new_release_page.placeholders.get()
165+ #add_plugin(placeholder, 'RawHtmlPlugin', 'en', body="<html goes here>")
166+ new_release_page.publish('en')
167+ RELEASE_PAGES[release_alias] = new_release_page
168
169
170 def import_branches():
171@@ -111,6 +174,7 @@
172 logging.error('No Snappy branches registered in the '
173 'SnappyDocsBranch table yet.')
174 return
175+ remove_old_pages()
176 tempdir = tempfile.mkdtemp()
177 pwd = os.getcwd()
178 os.chdir(tempdir)
179@@ -120,6 +184,7 @@
180 'Could not check out branch "%s".' % branch.branch_origin)
181 shutil.rmtree(os.path.join(tempdir, branch.path_alias))
182 break
183+ refresh_landing_page(branch.path_alias)
184 os.chdir(pwd)
185 for local_branch in [a for a in glob.glob(tempdir+'/*')
186 if os.path.isdir(a)]:

Subscribers

People subscribed via source and target branches

to all changes: