-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1049 from 18F/fixup-warnings
Document editor fixes
- Loading branch information
Showing
8 changed files
with
291 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import logging | ||
|
||
from django.core.management.base import BaseCommand | ||
from django.db import transaction | ||
from tqdm import tqdm | ||
|
||
from document.models import DocNode | ||
from document.tree import DocCursor | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def ensure_listitem_in_list(doc: DocCursor) -> DocCursor: | ||
"""We expect all listitems to have a parent list. However, the parser has | ||
emitted lists followed by bare listitems. We'll place the listitem in the | ||
list that imemdiately precedes it.""" | ||
for li in doc.filter(lambda n: n.node_type == 'listitem'): | ||
parent = li.parent() | ||
prev_sibling = li.left_sibling() | ||
|
||
if not parent: | ||
logger.warning('Root of %s is an li.', | ||
doc.policy.title_with_number) | ||
continue | ||
if parent.node_type == 'list': # all is well | ||
continue | ||
|
||
if prev_sibling and prev_sibling.node_type == 'list': | ||
li.append_to(prev_sibling) | ||
return ensure_listitem_in_list(doc) | ||
# else: create new list to wrap this one | ||
logger.warning('Could not fix li in %s', doc.policy.title_with_number) | ||
|
||
return doc # no changes needed | ||
|
||
|
||
def ensure_section_has_heading(doc: DocCursor) -> DocCursor: | ||
"""We expect all sections to have a heading. Fill the missing data with | ||
placeholder text.""" | ||
# materialize so we don't need to worry about a modified iterator | ||
secs = list(doc.filter(lambda n: n.node_type == 'sec')) | ||
for sec in secs: | ||
children = list(sec.children()) | ||
if not children or children[0].node_type != 'heading': | ||
sec.add_child('heading', insert_pos=0, text='--Missing Heading--', | ||
policy_id=doc.policy_id) | ||
return doc | ||
|
||
|
||
transforms = [ | ||
ensure_listitem_in_list, | ||
ensure_section_has_heading, | ||
] | ||
|
||
|
||
class Command(BaseCommand): | ||
help = ( # noqa (overriding a builtin) | ||
"Run through (idempotent) document migrations to mass-fixup docs.") | ||
|
||
def handle(self, *args, **kwargs): | ||
roots = DocNode.objects.filter(depth=0) | ||
with tqdm(total=roots.count()) as pbar: | ||
for root_docnode in roots: | ||
with transaction.atomic(): | ||
doc = DocCursor.load_from_model(root_docnode) | ||
for transform in transforms: | ||
doc = transform(doc) | ||
doc.nested_set_renumber(bulk_create=False) | ||
for node in doc.walk(): | ||
node.save() | ||
pbar.update(1) |
41 changes: 41 additions & 0 deletions
41
api/ombpdf/tests/test_management_commands_migrate_documents.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from document.tree import DocCursor | ||
from ombpdf.management.commands import migrate_documents | ||
|
||
|
||
def test_ensure_listitem_in_list(): | ||
root = DocCursor.new_tree('root') | ||
list_el = root.add_child('list') | ||
list_el.add_child('listitem', '1') | ||
root.add_child('listitem', '2') | ||
root.add_child('listitem', '3') | ||
assert [n.identifier for n in root.walk()] == [ | ||
'root_1', | ||
'root_1__list_1', | ||
'root_1__list_1__listitem_1', | ||
'root_1__listitem_2', | ||
'root_1__listitem_3', | ||
] | ||
|
||
root = migrate_documents.ensure_listitem_in_list(root) | ||
assert [n.identifier for n in root.walk()] == [ | ||
'root_1', | ||
'root_1__list_1', | ||
'root_1__list_1__listitem_1', | ||
'root_1__list_1__listitem_2', | ||
'root_1__list_1__listitem_3', | ||
] | ||
|
||
|
||
def test_ensure_section_has_heading(): | ||
root = DocCursor.new_tree('root') | ||
sec1 = root.add_child('sec') | ||
sec1.add_child('sec') | ||
sec12 = sec1.add_child('sec') | ||
sec12.add_child('heading', text='Subheading') | ||
root.add_child('sec') | ||
|
||
root = migrate_documents.ensure_section_has_heading(root) | ||
assert root['sec_1']['heading_1'].text == '--Missing Heading--' | ||
assert root['sec_1']['sec_1']['heading_1'].text == '--Missing Heading--' | ||
assert root['sec_1']['sec_2']['heading_1'].text == 'Subheading' | ||
assert root['sec_2']['heading_1'].text == '--Missing Heading--' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# -*- coding: utf-8 -*- | ||
# Generated by Django 1.11.5 on 2018-03-02 00:07 | ||
from __future__ import unicode_literals | ||
|
||
from django.db import migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('reqs', '0015_remove_policy_public'), | ||
] | ||
|
||
operations = [ | ||
migrations.RunSQL(""" | ||
UPDATE reqs_policy | ||
SET workflow_phase='cleanup' | ||
WHERE workflow_phase='no_doc' | ||
AND id IN (SELECT policy_id from document_docnode) | ||
""") | ||
] |