Merge pull request #104 from plone/maurits-remove-migration
Removed `comment-migration` view.
This commit is contained in:
commit
69ded592c3
@ -31,6 +31,10 @@ Bug fixes:
|
|||||||
user to fill in the form without validation error. Or when in the
|
user to fill in the form without validation error. Or when in the
|
||||||
control panel the field is set as not required anymore, that change
|
control panel the field is set as not required anymore, that change
|
||||||
would have no effect until the instance was restarted. [maurits]
|
would have no effect until the instance was restarted. [maurits]
|
||||||
|
- Removed ``comment-migration`` view. This did not work anymore on
|
||||||
|
Plone 5. If you still need to migrate from old-style comments, so
|
||||||
|
from Plone 4.0 or earlier, please upgrade to Plone 4.3 first.
|
||||||
|
[maurits]
|
||||||
|
|
||||||
|
|
||||||
2.4.14 (2016-06-06)
|
2.4.14 (2016-06-06)
|
||||||
|
@ -11,15 +11,6 @@
|
|||||||
<!-- Traversal adapter -->
|
<!-- Traversal adapter -->
|
||||||
<adapter factory=".traversal.ConversationNamespace" name="conversation" />
|
<adapter factory=".traversal.ConversationNamespace" name="conversation" />
|
||||||
|
|
||||||
<!-- Migration view -->
|
|
||||||
<browser:page
|
|
||||||
for="Products.CMFCore.interfaces.ISiteRoot"
|
|
||||||
name="comment-migration"
|
|
||||||
layer="..interfaces.IDiscussionLayer"
|
|
||||||
class=".migration.View"
|
|
||||||
permission="cmf.ManagePortal"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Moderation view -->
|
<!-- Moderation view -->
|
||||||
<browser:page
|
<browser:page
|
||||||
for="Products.CMFCore.interfaces.ISiteRoot"
|
for="Products.CMFCore.interfaces.ISiteRoot"
|
||||||
|
@ -49,25 +49,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="portalMessage warning"
|
|
||||||
tal:condition="view/unmigrated_comments_warning">
|
|
||||||
<strong i18n:translate="">
|
|
||||||
Warning
|
|
||||||
</strong>
|
|
||||||
<span tal:omit-tag="" i18n:translate="text_unmigrated_comments">
|
|
||||||
You have comments that have not been migrated to the new
|
|
||||||
commenting system that has been introduced in Plone 4.1.
|
|
||||||
Please
|
|
||||||
<tal:link i18n:name="label_comments_migration_link">
|
|
||||||
<a href=""
|
|
||||||
i18n:translate="text_comments_migration_link"
|
|
||||||
tal:attributes="href string:${view/site_url}/@@comment-migration"
|
|
||||||
>migrate your comments</a>
|
|
||||||
</tal:link>
|
|
||||||
to fix this.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
|
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
|
||||||
Portal status message
|
Portal status message
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,6 @@ from plone.app.discussion.upgrades import update_registry
|
|||||||
from plone.app.registry.browser import controlpanel
|
from plone.app.registry.browser import controlpanel
|
||||||
from plone.registry.interfaces import IRecordModifiedEvent
|
from plone.registry.interfaces import IRecordModifiedEvent
|
||||||
from plone.registry.interfaces import IRegistry
|
from plone.registry.interfaces import IRegistry
|
||||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
|
||||||
from Products.CMFCore.utils import getToolByName
|
from Products.CMFCore.utils import getToolByName
|
||||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||||
@ -182,15 +181,6 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
|||||||
return
|
return
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def unmigrated_comments_warning(self):
|
|
||||||
"""Returns true if site contains unmigrated comments.
|
|
||||||
"""
|
|
||||||
catalog = getToolByName(self.context, 'portal_catalog', None)
|
|
||||||
count_comments_old = catalog.searchResults(
|
|
||||||
object_provides=IDiscussionResponse.__identifier__)
|
|
||||||
if count_comments_old:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def notify_configuration_changed(event):
|
def notify_configuration_changed(event):
|
||||||
"""Event subscriber that is called every time the configuration changed.
|
"""Event subscriber that is called every time the configuration changed.
|
||||||
|
@ -1,283 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from Acquisition import aq_inner
|
|
||||||
from Acquisition import aq_parent
|
|
||||||
from datetime import datetime
|
|
||||||
from DateTime import DateTime
|
|
||||||
from plone.app.discussion.comment import CommentFactory
|
|
||||||
from plone.app.discussion.interfaces import IComment
|
|
||||||
from plone.app.discussion.interfaces import IConversation
|
|
||||||
from plone.app.discussion.interfaces import IReplies
|
|
||||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
|
||||||
from Products.CMFCore.utils import getToolByName
|
|
||||||
from Products.Five.browser import BrowserView
|
|
||||||
from types import TupleType
|
|
||||||
|
|
||||||
import transaction
|
|
||||||
|
|
||||||
|
|
||||||
def DT2dt(DT):
|
|
||||||
"""Convert a Zope DateTime (with timezone) into a Python datetime (GMT)."""
|
|
||||||
DT = DT.toZone('GMT')
|
|
||||||
return datetime(
|
|
||||||
DT.year(),
|
|
||||||
DT.month(),
|
|
||||||
DT.day(),
|
|
||||||
DT.hour(),
|
|
||||||
DT.minute(),
|
|
||||||
int(DT.second()))
|
|
||||||
|
|
||||||
|
|
||||||
class View(BrowserView):
|
|
||||||
"""Migration View
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __call__(self, filter_callback=None):
|
|
||||||
|
|
||||||
context = aq_inner(self.context)
|
|
||||||
out = []
|
|
||||||
self.total_comments_migrated = 0
|
|
||||||
self.total_comments_deleted = 0
|
|
||||||
|
|
||||||
dry_run = 'dry_run' in self.request
|
|
||||||
|
|
||||||
# This is for testing only.
|
|
||||||
# Do not use transactions during a test.
|
|
||||||
test = 'test' in self.request
|
|
||||||
|
|
||||||
if not test:
|
|
||||||
transaction.begin() # pragma: no cover
|
|
||||||
|
|
||||||
catalog = getToolByName(context, 'portal_catalog')
|
|
||||||
|
|
||||||
def log(msg):
|
|
||||||
# encode string before sending it to external world
|
|
||||||
if isinstance(msg, unicode):
|
|
||||||
msg = msg.encode('utf-8') # pragma: no cover
|
|
||||||
context.plone_log(msg)
|
|
||||||
out.append(msg)
|
|
||||||
|
|
||||||
def migrate_replies(context, in_reply_to, replies,
|
|
||||||
depth=0, just_delete=0):
|
|
||||||
# Recursive function to migrate all direct replies
|
|
||||||
# of a comment. Returns True if there are no replies to
|
|
||||||
# this comment left, and therefore the comment can be removed.
|
|
||||||
if len(replies) == 0:
|
|
||||||
return True
|
|
||||||
|
|
||||||
workflow = context.portal_workflow
|
|
||||||
oldchain = workflow.getChainForPortalType('Discussion Item')
|
|
||||||
new_workflow = workflow.comment_review_workflow
|
|
||||||
mt = getToolByName(self.context, 'portal_membership')
|
|
||||||
|
|
||||||
if type(oldchain) == TupleType and len(oldchain) > 0:
|
|
||||||
oldchain = oldchain[0]
|
|
||||||
|
|
||||||
for reply in replies:
|
|
||||||
# log
|
|
||||||
indent = ' '
|
|
||||||
for i in range(depth):
|
|
||||||
indent += ' '
|
|
||||||
log('{0}migrate_reply: "{1}".'.format(indent, reply.title))
|
|
||||||
|
|
||||||
should_migrate = True
|
|
||||||
if filter_callback and not filter_callback(reply):
|
|
||||||
should_migrate = False
|
|
||||||
if just_delete:
|
|
||||||
should_migrate = False
|
|
||||||
|
|
||||||
new_in_reply_to = None
|
|
||||||
if should_migrate:
|
|
||||||
# create a reply object
|
|
||||||
comment = CommentFactory()
|
|
||||||
comment.title = reply.Title()
|
|
||||||
comment.text = reply.cooked_text
|
|
||||||
comment.mime_type = 'text/html'
|
|
||||||
comment.creator = reply.Creator()
|
|
||||||
|
|
||||||
try:
|
|
||||||
comment.author_username = reply.author_username
|
|
||||||
except AttributeError:
|
|
||||||
comment.author_username = reply.Creator()
|
|
||||||
|
|
||||||
member = mt.getMemberById(comment.author_username)
|
|
||||||
if member:
|
|
||||||
comment.author_name = member.fullname
|
|
||||||
|
|
||||||
if not comment.author_name:
|
|
||||||
# In migrated site member.fullname = ''
|
|
||||||
# while member.getProperty('fullname') has the
|
|
||||||
# correct value
|
|
||||||
if member:
|
|
||||||
comment.author_name = member.getProperty(
|
|
||||||
'fullname'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
comment.author_name = comment.author_username
|
|
||||||
|
|
||||||
try:
|
|
||||||
comment.author_email = reply.email
|
|
||||||
except AttributeError:
|
|
||||||
comment.author_email = None
|
|
||||||
|
|
||||||
comment.creation_date = DT2dt(reply.creation_date)
|
|
||||||
comment.modification_date = DT2dt(reply.modification_date)
|
|
||||||
|
|
||||||
comment.reply_to = in_reply_to
|
|
||||||
|
|
||||||
if in_reply_to == 0:
|
|
||||||
# Direct reply to a content object
|
|
||||||
new_in_reply_to = conversation.addComment(comment)
|
|
||||||
else:
|
|
||||||
# Reply to another comment
|
|
||||||
comment_to_reply_to = conversation.get(in_reply_to)
|
|
||||||
replies = IReplies(comment_to_reply_to)
|
|
||||||
new_in_reply_to = replies.addComment(comment)
|
|
||||||
|
|
||||||
# migrate the review state
|
|
||||||
old_status = workflow.getStatusOf(oldchain, reply)
|
|
||||||
new_status = {
|
|
||||||
'action': None,
|
|
||||||
'actor': None,
|
|
||||||
'comment': 'Migrated workflow state',
|
|
||||||
'review_state': old_status and old_status.get(
|
|
||||||
'review_state',
|
|
||||||
new_workflow.initial_state
|
|
||||||
) or 'published',
|
|
||||||
'time': DateTime()
|
|
||||||
}
|
|
||||||
workflow.setStatusOf('comment_review_workflow',
|
|
||||||
comment,
|
|
||||||
new_status)
|
|
||||||
|
|
||||||
auto_transition = new_workflow._findAutomaticTransition(
|
|
||||||
comment,
|
|
||||||
new_workflow._getWorkflowStateOf(comment))
|
|
||||||
if auto_transition is not None:
|
|
||||||
new_workflow._changeStateOf(comment, auto_transition)
|
|
||||||
else:
|
|
||||||
new_workflow.updateRoleMappingsFor(comment)
|
|
||||||
comment.reindexObject(idxs=['allowedRolesAndUsers',
|
|
||||||
'review_state'])
|
|
||||||
|
|
||||||
self.total_comments_migrated += 1
|
|
||||||
|
|
||||||
# migrate all talkbacks of the reply
|
|
||||||
talkback = getattr(reply, 'talkback', None)
|
|
||||||
no_replies_left = migrate_replies(
|
|
||||||
context,
|
|
||||||
new_in_reply_to,
|
|
||||||
talkback.getReplies(),
|
|
||||||
depth=depth + 1,
|
|
||||||
just_delete=not should_migrate)
|
|
||||||
|
|
||||||
if no_replies_left:
|
|
||||||
# remove reply and talkback
|
|
||||||
talkback.deleteReply(reply.id)
|
|
||||||
obj = aq_parent(talkback)
|
|
||||||
obj.talkback = None
|
|
||||||
log('{0}remove {1}'.format(indent, reply.id))
|
|
||||||
self.total_comments_deleted += 1
|
|
||||||
|
|
||||||
# Return True when all comments on a certain level have been
|
|
||||||
# migrated.
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Find content
|
|
||||||
brains = catalog.searchResults(
|
|
||||||
object_provides='Products.CMFCore.interfaces._content.IContentish')
|
|
||||||
log('Found {0} content objects.'.format(len(brains)))
|
|
||||||
|
|
||||||
count_discussion_items = len(
|
|
||||||
catalog.searchResults(Type='Discussion Item')
|
|
||||||
)
|
|
||||||
count_comments_pad = len(
|
|
||||||
catalog.searchResults(object_provides=IComment.__identifier__)
|
|
||||||
)
|
|
||||||
count_comments_old = len(
|
|
||||||
catalog.searchResults(
|
|
||||||
object_provides=IDiscussionResponse.__identifier__
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
log(
|
|
||||||
'Found {0} Discussion Item objects.'.format(
|
|
||||||
count_discussion_items
|
|
||||||
)
|
|
||||||
)
|
|
||||||
log('Found {0} old discussion items.'.format(count_comments_old))
|
|
||||||
log(
|
|
||||||
'Found {0} plone.app.discussion comments.'.format(
|
|
||||||
count_comments_pad
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
log('\n')
|
|
||||||
log('Start comment migration.')
|
|
||||||
|
|
||||||
# This loop is necessary to get all contentish objects, but not
|
|
||||||
# the Discussion Items. This wouldn't be necessary if the
|
|
||||||
# zcatalog would support NOT expressions.
|
|
||||||
new_brains = []
|
|
||||||
for brain in brains:
|
|
||||||
if brain.portal_type != 'Discussion Item':
|
|
||||||
new_brains.append(brain)
|
|
||||||
|
|
||||||
# Recursively run through the comment tree and migrate all comments.
|
|
||||||
for brain in new_brains:
|
|
||||||
obj = brain.getObject()
|
|
||||||
talkback = getattr(obj, 'talkback', None)
|
|
||||||
if talkback:
|
|
||||||
replies = talkback.getReplies()
|
|
||||||
if replies:
|
|
||||||
conversation = IConversation(obj)
|
|
||||||
log('\n')
|
|
||||||
log(
|
|
||||||
'Migrate "{0}" ({1})'.format(
|
|
||||||
obj.Title(),
|
|
||||||
obj.absolute_url(relative=1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
migrate_replies(context, 0, replies)
|
|
||||||
obj = aq_parent(talkback)
|
|
||||||
obj.talkback = None
|
|
||||||
|
|
||||||
if self.total_comments_deleted != self.total_comments_migrated:
|
|
||||||
log(
|
|
||||||
'Something went wrong during migration. The number of '
|
|
||||||
'migrated comments ({0}) differs from the number of deleted '
|
|
||||||
'comments ({1}).'.format(
|
|
||||||
self.total_comments_migrated,
|
|
||||||
self.total_comments_deleted
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not test: # pragma: no cover
|
|
||||||
transaction.abort() # pragma: no cover
|
|
||||||
log('Abort transaction') # pragma: no cover
|
|
||||||
|
|
||||||
log('\n')
|
|
||||||
log('Comment migration finished.')
|
|
||||||
log('\n')
|
|
||||||
|
|
||||||
log(
|
|
||||||
'{0} of {1} comments migrated.'.format(
|
|
||||||
self.total_comments_migrated,
|
|
||||||
count_comments_old
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.total_comments_migrated != count_comments_old:
|
|
||||||
log(
|
|
||||||
'{0} comments could not be migrated.'.format(
|
|
||||||
count_comments_old - self.total_comments_migrated
|
|
||||||
)
|
|
||||||
) # pragma: no cover
|
|
||||||
log('Please make sure your ' +
|
|
||||||
'portal catalog is up-to-date.') # pragma: no cover
|
|
||||||
|
|
||||||
if dry_run and not test:
|
|
||||||
transaction.abort() # pragma: no cover
|
|
||||||
log('Dry run') # pragma: no cover
|
|
||||||
log('Abort transaction') # pragma: no cover
|
|
||||||
if not test:
|
|
||||||
transaction.commit() # pragma: no cover
|
|
||||||
return '\n'.join(out)
|
|
Loading…
Reference in New Issue
Block a user